Vue基础(16)_Vue侦听数据改变的原理(对象)、Vue.set/vm.$set方法的使用
上一节引出问题,Vue如何监测数组元素改变?问题解决前,我们先研究Vue如何监测对象中的属性改变。
分析Vue中对象数据:
<div id="root"><h3>姓名:{{name}} </h3><h3>地址:{{address}}</h3></div><script>const vm = new Vue({el: '#root',data: {name: '张三',address: '北京'}})</script>
Vue如何实现数据侦听?分析:
用户输入的data配置项,执行时:
1、Vue对data进行了加工(使数据具有响应式)。
2、赋值:_data = data。3、用户查询或修改数据时,Vue通过数据代理,间接调用的_data中get/set,从而重新解析模板,生成虚拟DOM,通过Diff算法进行新旧DOM对比,最后更新页面。
模拟一个简单的对象数据侦听:
<script>let data = {name: '张三',address: '北京'}// Observer:观察者。创建一个监视的实例对象,用于监视data中属性的变化const obs = new Observer(data)console.log(obs);// 准备一个vm实例对象let vm = {};vm._data = data = obs;function Observer(obj) {// 汇总对象中所有的属性,形成一个数组const keys = Object.keys(obj);// 遍历keys.forEach((k) => {Object.defineProperty(this, k, {get() {return obj[k]},set(val) {console.log(`${k}被改了,我要去解析模板,生成虚拟DOM,进行Diff算法比较...我要开始忙了`)obj[k] = val}})})}</script>
与Vue底层代码相比,Vue设计更为完善,添加了更多功能:
1、Vue底层添加了数据代理(vm.name、vm.address)。
2、Vue底层运用递归,给【对象】、【对象数组】里的属性、子属性、子孙属性...添加了不限层次的响应式功能的get/set(age.rAge、age.sAge...)
Vue.set的使用(向对象添加响应式属性和值)
尽管Vue底层做得很完善,但是也有不足的地方。例如:
<!DOCTYPE html>
<html lang="zh"><head><meta charset="UTF-8"><title>Vue.set的使用</title><script type="text/javascript" src="../js/vue.js"></script>
</head><body><div id="root"><h2 style="color:chocolate">学校信息</h2><h3>学校名称:{{name}}</h3><h3>学校地址:{{address}}</h3><hr><h2 style="color:chocolate">学生信息</h2><h3>姓名:{{student.name}}</h3><h3 v-if="student.sex">性别:{{student.sex}}</h3><h3>年龄:真实{{student.age.rAge}},对外{{student.age.sAge}}</h3><h3>朋友:</h3><ul><li v-for="(f,index) in student.friends" :key="index">{{f.name}}--{{f.age}}</li></ul><button @click="addStudentSex">添加学生性别</button></div>
</body>
<script>const vm = new Vue({el: '#root',data: {name: '江西师范大学',address: '南昌市瑶湖校区',student: {name: '张三',age: {rAge: 30,sAge: 18,},friends: [{ name: 'jerry', age: 35 },{ name: 'tony', age: 32 }]}},methods: {addStudentSex() {// this.$set(this.student,'sex','男'),Vue.set(this.student,'sex','男')}}})
</script></html>
直接向vm._data.student或vm.student中添加属性不具有响应式功能:
通过对Vue.set/vm.$set这类api的使用,能使得添加的对象属性具有响应式:
不能向Vue 实例,或者 Vue 实例的根数据对象添加属性:
Vue.set/vm.$set的使用
Vue.set( target, propertyName/index, value )
vm.$set( target, propertyName/index, value )
参数:
{Object | Array} target
{string | number} propertyName/index
{any} value
返回值:设置的值。用法:
向响应式对象中添加一个 property,并确保这个新 property 同样是响应式的,且触发视图更新。它必须用于向响应式对象上添加新 property,因为 Vue 无法探测普通的新增 property (比如 this.myObject.newProperty = 'hi')
注意:对象不能是 Vue 实例,或者 Vue 实例的根数据对象。