【问题标题】:Accessing computed properties of child components in Vue在 Vue 中访问子组件的计算属性
【发布时间】:2018-08-03 16:13:04
【问题描述】:

访问子组件的计算属性的正确方法是什么?下面是我正在尝试实现的简化示例(也可在 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 和计算总和)中的值之后,它不能很好地反映父组件(生成的 JSON)中的更改。

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

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

【问题讨论】:

    标签: javascript vue.js vuejs2 vue-component


    【解决方案1】:

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

    这是一个例子。

    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>

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

    【讨论】:

    • 我运行了您的示例,但它似乎不起作用(您还缺少新推送对象中的方法定义)-此外,您不会因为放弃计算属性而失去 vue 提供的反应性和改用常规对象方法?
    • @Zaroth 哪个部分不完全工作?对我来说似乎工作正常。没有。
    • 子组件未正确显示sum - 可能是因为子模板中的{{this.sum}} 部分需要更改为{{value.sum()}}
    • @Zaroth 是的,我错过了那个。应该是固定的。
    【解决方案2】:

    你的父母不更新的原因是你是adding a property to an object, which Vue doesn't detect

    代替

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

    你会的

    sum() {
        const s = Number(this.value.a) + Number(this.value.b)
        this.$set(this.value, 'sum', s);
        return s;
    }
    

    尽管在计算和更新道具中的值有副作用的代码气味,这表明你应该做一些不同的事情。

    【讨论】:

      猜你喜欢
      • 2020-09-30
      • 1970-01-01
      • 1970-01-01
      • 2019-07-29
      • 2018-01-14
      • 2019-03-16
      • 2018-03-24
      • 2013-07-08
      • 2018-01-22
      相关资源
      最近更新 更多