访问 Vue 中子组件的计算属性

Zar*_*oth 5 javascript vue.js vue-component vuejs2

访问子组件的计算属性的正确方法是什么?下面是我想要实现的目标的简化示例(也可在JSFiddle上找到):

const FoobarWidget = {
    template: '<li>a: <input type="text" v-model="value.a" style="width:2em;"> b: <input type="text" v-model="value.b" style="width:2em;"> sum: {{this.sum}} <button @click="die">x</button></li>',
    props: {
        value: {
            type: Object,
            required: true,
        }
    },
    computed: {
        sum() {
            const s = Number(this.value.a) + Number(this.value.b)
            // WARNING eslint - vue:no-side-effects-in-computed-properties
            this.value.sum = s;
            return s;
        }
    },
    methods: {
        die() {
            this.$emit('die');
        }
    }
};

new Vue({
    el: '#app',
    data: {
        foobars: [{
            a: '5',
            b: '6'
        }],
    },
    components: {
        FoobarWidget,
    },
    computed: {
        myJson() {
            return JSON.stringify(this.foobars, null, 2);
        }
    },
    methods: {
        addNew() {
            this.foobars.push({
                a: '1',
                b: '2'
            });
        },
        foobarDead(index) {
            this.foobars.splice(index, 1);
        }
    }
});
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
  <button @click="addNew()">add foobar</button>
  <h3>Foobars</h3>
  <ul>
    <foobar-widget v-for="(foobar, index) in foobars" :key="index" @die="foobarDead(index)" v-model="foobars[index]"/>
  </ul>
  <h3>JSON</h3>
  <pre>{{myJson}}</pre>
</div>
Run Code Online (Sandbox Code Playgroud)

正如尝试此示例后所看到的,它基本上可以工作 - 但在更改子组件(a、b 和计算总和)中的值后,它不能很好地反映父组件(生成的 JSON)中的更改。

这个问题似乎与SO: Computed property on child component props类似,但是该问题的 OP 有一个进行字符串格式化的计算值,使用 Vue 过滤器是一个很好的解决方案。这里的情况并非如此 -sum()计算属性可以是任意函数,需要在父组件和子组件中访问。

我上面的方法,通过在sum重新计算时添加属性来修改 prop 对象,绝对不是正确的方法,因此我的问题。它不仅工作不稳定,而且还会产生 ESLint 警告(WARNING上面代码中的注释)。

Ber*_*ert 2

我建议你在这里采取了错误的方法。如果您想要一个属性是对象上值的总和,请将该属性添加到对象,而不是组件。

这是一个例子。

const FoobarWidget = {
  template: '<li>a: <input type="text" v-model="value.a" style="width:2em;"> b: <input type="text" v-model="value.b" style="width:2em;"> sum: {{value.sum}} <button @click="die">x</button></li>',
  props: {
    value: {
      type: Object,
      required: true,
    }
  },
  methods: {
    die() {
      this.$emit('die');
    }
  }
};

const foo = {
  a: 5,
  b: 6,
  // define your property here
  get sum() {
    return +this.a + +this.b
  }
}

new Vue({
  el: '#app',
  data: {
    foobars: [foo],
  },
  components: {
    FoobarWidget,
  },
  methods: {
    addNew() {
      this.foobars.push({
        a: '1',
        b: '2',
        get sum() {
          return +this.a + +this.b;
        }
      });
    },
    foobarDead(index) {
      this.foobars.splice(index, 1);
    }
  }
});
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
  <button @click="addNew()">add foobar</button>
  <h3>Foobars</h3>
  <ul>
    <foobar-widget v-for="(foobar, index) in foobars" :key="index" @die="foobarDead(index)" v-model="foobars[index]" />
  </ul>
  <h3>JSON</h3>
  <pre>{{foobars}}</pre>
</div>
Run Code Online (Sandbox Code Playgroud)

使用这种方法,您永远不需要访问组件的计算属性。