问题示例:https://jsfiddle.net/hxv5bLqt/
我有一个包含2个级别(数组)的数据结构。第一级是“部分”,第二级是“项目”,它们位于每个“部分”内。还有一个变量存储每个项目值的总值。示例工作如下:每次用户在某个值字段中键入内容或删除值时,必须重新计算总数。
但是,我对示例解决方案不满意,因为我需要映射应该调用“this.recompute()”方法的所有地方,并且通过监视或计算属性,这可以解决以更清晰的方式,清洁和反应。
但是,我无法实现“监视”或“计算属性”,可以看到数组内部对象属性的更改。
对于“手表”案例,我认为理想和我认为可行的是:
watch: {
'parts.X.items.Y.value': function(oldValue, newValue) {
this.recompute()
}
}
“X”和“Y”表示要观察的字段位于数组的任何位置的变量。
这样,每次用户点击按钮删除项目或在值字段中键入内容时,都会触发手表。但这不起作用。
这样,每次用户点击按钮删除项目或在值字段中键入内容时,都会触发手表。但是这不起作用,我需要映射应该调用“this.recompute()”方法的所有点,如下所示:
onClickRemoveItem(event, part, item) {
...
this.recompute() // RECOMPUTE HERE.
},
onKeyupItemValue(event) {
this.recompute() // RECOMPUTE HERE.
},
我认为这不是解决问题的好方法,因为如果还有10个地方应该调用“this.recompute()”方法,那么很难记住所有的调用位置。
有一种方法可以更优雅的方式做到这一点吗?
答案 0 :(得分:0)
如果你使你的总数成为计算属性,那么你可以免费获得更多的反应性(意味着你不必监听项目值的更新或明确地重新计算任何东西)。请参阅此处的答案以了解具体实施:https://jsfiddle.net/16wk9gre/
HTML
<script src="https://unpkg.com/vue"></script>
<div id="app">
<h3>Tests</h3>
<ul>
<li v-for="part in parts">
<span>{{ part.name }}</span>
<ul>
<li v-for="item in part.items">
R$ <input type="number" v-model="item.value">
<button type="button" @click="onClickRemoveItem($event, part, item)">Remove</button>
</li>
<p>
Part subtotal: ${{ part.items.reduce((acc, item) => acc + parseFloat(item.value), 0) }}
</p>
<p>
Part subtotal (alternate): ${{ calculatePartSubtotal(part.items) }}
</p>
</ul>
</li>
</ul>
<p><strong>Total value:</strong>R$ {{ total }}</p>
</div>
JS
new Vue({
el: '#app',
data() {
return {
// Define some nested mock data.
parts: [
{ id: 1, name: 'Part 1', items: [{ id: 1, value: 10.00 }, { id: 2, value: 5.00 }] },
{ id: 2, name: 'Part 2', items: [{ id: 3, value: 15.00 }] }
]
}
},
computed: {
total () {
let total = 0.0
for (let i = 0; i < this.parts.length; i++) {
for (let j = 0; j < this.parts[i].items.length;; j++) {
total += parseFloat(this.parts[i].items[j].value)
}
}
return total
}
},
methods: {
calculatePartSubtotal (items) {
return items.reduce((acc, item) => acc + parseFloat(item.value), 0)
},
// Remove an item of a part.
onClickRemoveItem(event, part, item) {
let index = part.items.findIndex(e => e.id === item.id)
this.$delete(part.items, index)
}
}
})