VUE响应式
- 什么是vue的响应式?
数据变化,页面也会更新
VUE响应式的意思就是这么简单,本文会以下面代码为基础,进行自问自答,深度探究。
<div id="app">
<div>{{ head }}</div>
<ul>
<li>{{ "姓名:"+ obj.name }}</li>
<li>{{ "年龄:"+ obj.age }}</li>
<li>{{ "性别:"+ obj.sex }}</li>
</ul>
<div>{{ arr }}</div>
</div>
var vm = new Vue({
el: '#app',
data: {
head: 'hello today',
obj: {
name: 'ludeng',
age: 18,
sex: 'male'
},
arr: [1, 2, 3, 4]
}
})
我们在控制台打印vm

你会发现,vm里有我们在data里定义的数据!打印head数据,可以显示

那么,问题来了
- 问:为什么可以直接通过vm.xxx访问data里的数据,而不是vm.data.xxx?
便于监控数据变化 实现响应式。
vm.data.xxx比vm.xxx多了一个点!😱多恐怖,主要是监控起来麻烦还多消耗性能(毕竟多一层),把所有需要监测的(不只data里,还有methods等),直接代理给vm实例,然后只监测vm,它不香吗?
好奇的同学可能被控制台的一坨$开头变量吸引了
- 问:实例中除了data数据外,其他东西是啥子?
就是个普通变量而已,只不过为了防止名称冲突,vue会把自己内部的属性成员名称前加上$或_,如果加上的是$,代表是我们可以使用的,如果加上的是_,是vue自己内部使用的方法或属性,我们不需要调用
好了,我们继续探讨vue响应式,我提个问题,更改数据后,页面会立刻重新渲染吗?有哪位同学会,会的请举手?小明:"会"。你坐下吧,不对。
- 问:更改数据后,页面会立刻重新渲染吗?
如果做个1000次循环,修改一个数据1000次,难道页面要重新渲染1000次?vue更新DOM的操作是异步执行的,只要侦听到数据变化,将开启一个异步队列,如果一个数据被多次变更,那么只会被推入到队列中一次,这样可以避免不必要的计算和DOM操作。
在js源代码上加两句,运行
vm.head = "hello new day";
console.log(vm.$el.innerHTML); //相当于document.getElementById('app').innerHTML

页面已经变了,为什么打印出来的是原来的东西(hello today 而不是 hello new day)?
产生上面现象是还是因为vue是异步渲染,所以上面同步代码执行,打印vm.$el.innerHTML时,还未重新渲染(如果看不懂再去学习下js事件循环)
- 问:如何在更改数据后,看到渲染后的页面上的值?
利用
vm.$nextTick,在页面重新渲染,DOM更新后,会调用vm.$nextTick回调函数
vm.head = "hello new day";
console.log(vm.$el.innerHTML);
vm.$nextTick(()=>{
console.log(vm.$el.innerHTML)
})

执行上面代码,使用vm.$nextTick可以准确打印出
- 问:nextTick是怎么实现的?
在nextTick的实现源码中,会先判断是否支持微任务,不支持后,才会执行宏任务
| Promise -> MutationObserver -> setImmediate -> setTimeout |依次判断是否支持,如果支持Promise,就用promise执行$nextTick,(IE)不支持就用后面的
- 问:什么数据更改后不会渲染页面?
- 未被声明过(obj.aaaa)和未被渲染的数据
- 利用索引直接设置一个数组项/修改数组的长度时
- 添加或删除对象

如上图,修改对象会渲染页面,但添加删除对象不会,利用索引修改数组项也不会更新。最后我们打印出obj和arr,可以发现值成功修改,只是没有更新页面
- 问:要如何响应式的更新数组和对象?
- 更改对象
- 利用
vm.$set(Vue.set) 增改 - 利用
vm.$set(Vue.set) 删除
- 利用
- 更改数组:
- 利用数组变异方法:push、pop、shift、unshift、splice、sort、reverse
- 用
vm.$set和vm.$delete(一般变异数组就够了)
- 更改对象
- vm.
set(object, propertyName, value)
- vm.
delete(object, target)

数组有更好的方法,就是使用push、pop等方法更新数据,也就是上面说的变异数组,为什么叫变异数组,因为使用它们本身使用不会重新渲染,vue进行了处理,使得调用push、pop等方法时,会渲染页面。如下图效果,页面会渲染,其他方法一样。

- 但为什么上面在不使用
vm.$set和vm.$delete情况下,不重新渲染页面?
Object.defineProperty的锅,vue2.0利用Object.defineProperty实现响应式,下文剖析VUE响应式原理