访问子组件的计算属性的正确方法是什么?以下是我要实现的简化示例(也可以在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);
        }
    }
});
<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>


正如尝试这个示例后所看到的,它大部分都可以工作-只是在更改子组件(a,b和计算所得的和)中的值后,它不能很好地反射(reflect)父组件(生成的JSON)中的更改。

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

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

最佳答案

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

这是一个例子。

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);
    }
  }
});
<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>


使用这种方法,您无需访问组件的计算属性。

09-20 23:53