通常,在使用Vue时,我希望仅当该属性的值更改时才触发监视属性的回调。但是,一位同事注意到,在观看计算的属性时,这似乎并不成立,如以下示例所示:
<div id = "demo">
{{ numbers }} </br>
{{ evenNumbers }}
</div>
<script src="./vue.js"></script>
<script>
var demo = new Vue({
el: '#demo',
data: function(){
return {
numbers: [1,2,3,4,5,6]
};
},
computed: {
evenNumbers: function () {
return this.numbers.filter(x => (x % 2 == 0))
}
},
watch: {
evenNumbers: function (val) {
alert("yes, computed property changed")
}
}
})
setTimeout(() => { demo.numbers.push(7) }, 5000)
</script>
5s之后,将显示警报,但计算所得的数字数组的值不会更改。试图推断出,如果计算属性的依赖关系更新了,即使没有计算属性本身的依赖关系,也会触发监视程序。
事实证明,这很适合我们正在处理的应用程序,但我不了解其行为,也不知道我们是否可以依靠它,或在什么条件下可以使用它。 (例如,我在这里有两个数组,但是如果我包含原始元素,它仍然可以工作吗?我不知道,如果有时间我可以尝试,但是比较对象相等性的问题只是发生在第一件事我在键入此命令时遇到了我,第二个是Vue的反应性和复合对象的陷阱。)我还可以想象,如果回调给观察者是一项昂贵的操作,可能会令人不快。
如果有人能解释它是如何工作的,并且我们可以依靠这种行为,我将不胜感激。
答案 0 :(得分:1)
触发该观察程序是因为它无法知道data.numbers
上的更改是否会影响computed.evenNumbers
的结果。
但是,重新计算后发现7不为偶数,因此数组保留为[2, 4, 6]
。
如果要确保仅在值实际更改时才运行回调,可以将其指定为
watch: {
evenNumbers(newValue, oldValue){
if(newValue !== oldValue) {
alert('callback')
}
}
}
答案 1 :(得分:0)
每次执行evenNumbers()
时,都会生成一个全新的数组。由于数组是通过引用相等性进行比较的,因此它们永远不能相等。正确检测此更改的唯一方法是手动将先前计算的数组的内容与新计算的数组进行比较。
使用lodash的示例:
import { isEqual } from 'lodash';
...
watch: {
evenNumbers(newValue, oldValue) {
if(!isEqual(newValue, oldValue) {
alert('callback')
}
}
}