这是我参与8月更文挑战的第31天,活动详情查看:8月更文挑战
问题起源
起源于最近的生产项目,父组件向子组件传递一个Object数据,因为这个Object数据太多,于是我“偷懒”了一下,在子组件的data中是这样写的:
...
data () {
return {
content: {}
}
}
...
没想到,就是因为这一行代码花费了一个下午来找响应问题:怎么数据更新了以后,子组件数据没有变化呢?
由此引导我重新认识VUE的深度响应原理。原文文档比我写的要详细。下面我们介绍一些实用的内容,即在实际工作中能用到的东西。
话说现在VUE3都上线了,我VUE2还没学太会,是不是太菜了。
因此,我们来重新认识一下关于VUE中的Object与数组监听问题。
实验
Object监听问题重现
在VUE官方文档中说:
由于 JavaScript 的限制,Vue 不能检测数组和对象的变化。
那么,什么叫“不能检测”呢?
请看下面的实验代码:
<!DOCTYPE html>
<head>
<script src="http://unpkg.com/vue/dist/vue.js"></script>
<script src="http://unpkg.com/element-ui@2.15.5/lib/index.js"></script>
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
</head>
<body>
<div id="app">
<template>
<div>
{{message}}
</div>
<div>
对象: {{obj}}
</div>
<div>
computed: obj.a = {{objA}}
</div>
<div>
computed: obj.c = {{objC}}
</div>
<el-button type="primary" @click="changeData">更新数据</el-button>
</template>
</div>
<script>
var Main = {
data() {
return {
message: '数据修改前:',
obj: {
a: 1,
b: 2
}
}
},
computed: {
objA() {
return this.obj.a
},
objC() {
return this.obj.c
}
},
methods: {
changeData() {
this.obj.c = '2';
this.message = '数据修改后:'
}
}
}
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')
</script>
</body>
</html>
我们先看一下效果:
可以看到,obj.a的属性值变化影响到了computed中的objA,而obj.c的赋值操作却没有影响。
原因在哪里呢?
原因就在于其中的data,我在定义data中的obj时,只给了两个属性:a与b,而在后续点击操作更新数据的时候,我们是这样设置obj.c的:
this.obj.c = '2'
没有处罚computed更新对应的objC的值。
我们根据官方提示,使用另外一种方式设置尝试一下: 即将上述更新c值的方式修改为:
this.$set(this.obj, 'c', 'cvalue')
再来看看效果:
可以明显的看到,相对应的objC也响应了变化。
数组的变化了类似,对于数据,一方面是注意监听的问题,另一方面是需要注意,数组某些方法会触发视图监听:在VUE的文档中列的很详细:如push等系列函数,而通过list[i]修改元素值不会触发侦听,这里就不再赘言。