【问题标题】:VueJs computed property without caching没有缓存的 VueJs 计算属性
【发布时间】:2018-09-27 04:16:38
【问题描述】:

我有一个组件,它是一个输入字段,它接受三种情况并将它们转换为内部状态(数字):

  • 输入:无(空字符串);状态:未定义;类:是空的;值:空字符串
  • 输入:任意正数;状态:正数;类:;值:正数
  • 输入:-;状态:-1;类:未知;值:-
  • 否则:状态:-2;类:是无效的;值:空字符串

这个组件有一个output 计算属性,它有一个改变内部状态的setter 和一个根据内部状态在无效时返回数字、破折号或空字符串的getter。特殊情况是我希望将字段保留为空的无效输入。

对于第一个无效字符,它工作得很好,但是下一个会显示在字段中。我怀疑这个值被缓存了,因为内部状态保持在invalid,因此使用了缓存。

<template>
  <input v-model="output" v-bind:class="state"/>
</template>

<script>
export default {
  name: 'TsResult',
  props: ['result'],
  data: function() {
    return {
      res: this.result
    }
  },
  computed: {
    state: function() {
      // ..
      if (this.res === -2) {
        return 'is-invalid'
      } else if (this.res === -1) {
        return 'is-unknown'
      }
      // ...
    },
    'output': {
      set: function(newVal) {
        //.. 
        if (isInvalid(newVal)) {
           this.res = -2;
        } else if (isUnknwon(newVal)) {
           this.res = -1;
        }
        // ...
      },
      get: function() {
        if (this.res === -2 ) { // Invalid
          return ''
        } else if (this.res === -1) { // Unknown
          return '-'
        } 
        // ...
      }
    }
</script>

使用方法而不是计算的 getter 不适用,因为我需要 setter 来执行验证。

并且使用观察者不是一个好主意,因为无效状态会改变输入值(通过设置一个空字符串)并重新触发接受空字符串的观察者。所以永远不会显示无效状态。

我可以禁用此计算属性的缓存还是有更好的选择?

一个可能的技巧是减少无效状态的内部状态,以便内部状态发生变化并重新计算值。但我希望有更好的解决方案。

【问题讨论】:

  • 请提供代码示例

标签: vue.js vuejs2 vue-component


【解决方案1】:

cache 属性设置为false 应该禁用计算属性的缓存。详情见issue #1189 - Make computed property caching optionalrelevant commit

也许您可以覆盖一个接收实际按键的不可见输入字段并将计算的属性输出到较低的显示属性?

v-model 拆分为v-bindv-on:input 怎么样,大致类似(添加缺少的函数来测试它):

<template>
  <input v-bind:value="output_computed()" v-on:input="on_input($event.target.value)" v-bind:class="state"/>
</template>

<script>
function isValid(val) {
  return parseInt(val) != NaN && parseInt(val) >= 0;
}

function isInvalid(val) {
  return parseInt(val) == NaN || parseInt(val) < 0;
}

function isUnknown(val) {
  return !(isValid(val) || isInvalid(val));
}

export default {
  name: "TsResult",
  props: ["result"],
  data() {
    return {
      res: this.result,
      v: ""
    };
  },
  methods: {
    output_computed() {
      if (this.res === -2) {
        // Invalid
        return "";
      } else if (this.res === -1) {
        // Unknown
        return "-";
      } else if (this.res === -3) {
        return "";
      } else if (this.res === 0) {
        return this.v;
      }
    },
    on_input(newVal) {
      if (isInvalid(newVal)) {
        this.res = -2;
      } else if (isUnknown(newVal)) {
        this.res = -1;
      } else if (newVal === "") {
        this.res = -3;
      } else if (isValid(newVal)) {
        this.res = 0;
        this.v = newVal;
      }
      this.$emit("input", this.output_computed());
    }
  }
};
</script>

你可以看到它直播here on codesandbox.io

【讨论】:

  • 它已被弃用,但它应该仍然存在。如果您想避免它,是否适合您使用带有 setter 的属性进行验证,并使用常规方法进行输出(从而避免缓存)?
  • 不想使用已弃用的功能。方法加 setter 解决方案不起作用。我们可以为同一个属性提供一个计算的 setter 和一个方法吗?
  • 不,但是为什么不能为两者使用不同的名称呢? setter 会设置一个内部变量,然后方法会返回它
  • 如何告诉我在我的模板中将一个属性绑定为输入,而将另一个属性绑定为输出?我的模板是&lt;input v-model="output"&gt;(请参阅我的问题中的编辑)。 编辑: 没有阅读您的答案。会试试的
猜你喜欢
  • 1970-01-01
  • 2018-11-12
  • 2017-08-23
  • 1970-01-01
  • 2020-02-05
  • 2020-06-19
  • 2019-06-22
  • 2020-03-27
  • 2019-02-11
相关资源
最近更新 更多