访问子组件的计算属性的正确方法是什么?以下是我尝试实现的简化示例(也可在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);
}
}
});
&#13;
<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>
&#13;
在尝试这个例子之后可以看到,它主要起作用 - 除了在更改子组件中的值(a,b和计算的总和)之后它没有很好地反映父组件(生成的JSON)中的变化)。
问题似乎与SO: Computed property on child component props类似,但该问题的OP具有执行字符串格式化的计算值,使用Vue过滤器是一个很好的解决方案。这不是这种情况 - sum()
计算属性可以是任意函数,需要在父组件和子组件中访问它。
我上面的方法,通过在重新计算时添加sum
属性来修改prop对象绝对不是正确的方法,因此我的问题。它不仅运行困难,而且还产生ESLint警告(上面代码中的WARNING
注释)。
答案 0 :(得分: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>
使用此方法,您永远不需要访问组件的计算属性。
答案 1 :(得分:1)
您父母没有更新的原因是您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;
}
尽管计算中存在副作用的代码气味,并且在道具中更新了值,这表明你应该采取不同的做法。