Appearance
什么是虚拟 DOM
- 是对真实 DOM 的引射,就是一个对象
为什么要有虚拟 DOM
- 真实 DOM 上有一堆的属性和方法,直接操作真实的 DOM 每次都会导致重绘和回流,所以性能差; 操作虚拟 DOM 不存在性能问题,因为他是等数据全部更新完毕之后,只会更新真实 DOM 树需要改变的地方,只有一次重绘和回流
- 组件初始化的时候创建一个虚拟 DOM 树,数据更新时生成一个新的虚拟 DOM 树,利用 diff 算法广度遍历对新旧 DOM 树一层一层的进行比较
- diff 算法
- 如果是元素变了,删除元素,创建新的元素
- 如果属性或内容变了,修改属性和内容
- 使用 v-for 遍历的时候
- 没有 key 的时候或者 Key 是索引的时候,diff 算法会采用就地复用的原则,再顺序上位置是同一个索引会被认为是同一个元素,使用改变数据顺序的方法的时候,就会导致不需要更新的元素也会更新
- 当给 key 的值是唯一标识的时候 ,它通过diff算法进行比较的时候能够通过key值最快速的去找到哪个变化的Dom元素从而对它进行修改
- 虚拟 DOM 的作用:可以实现高效更新(数据变了的时候视图更新效率更高),可以实现跨平台(一套代码可以生成不同的平台的最终代码)
数据响应式的原理
- 数据响应式就是数据变了,视图跟着变 利用 Object.defineProperty 数据劫持和观察者模式来实现的
- Object.defineProperty 里面有一个 get 和 set 方法。 get 可以返回被劫持的属性的值,set 可以修改被劫持的属性的值,在数据初始化的时候把 data 里面的数据进行转换,每个数据创建一个 Dep(被观察者)
- 对模板进行编译 (compiler) 提取里面所有需要数据的地方变成 watcher (观察者),然后把 watcher(观察者) 加入到对应的 Dep(被观察者) 的观察者列表中
- 当 data 中某个属性变化的时候,由于被劫持了,所以 vue 内部是知道的,就会调用对应的 dep(被观察者) 去通知观察者列表中所有的观察者 然后观察者去更新视图
- 存在的问题:
新增属性 删除属性界面不会更新
直接通过下标修改数组界面不会更新
原因: 读取数据会调用getter()修改数据调用setter() 所以新增和删除属性object.difineProperty是监测不到的 - 解决办法:
- 使用this.$set(要操作的数据,要修改的下标(或要增加的属性),修改(或新增的是什么)成什么)或者用Vue.set()这个API
删除的话使用this.$delete()或者Vue.delete()API - 修改数组下标还可以使用数组的splice()方法
- 不响应又响应的情况是:比如再修改数组下标或给对象新增属性 后面又操作了其他数据 此时是可以拿到更新后的数据的 因为后面操作了其他的数据当数据发生变化 组件就会更新 组件更新 页面也会更新 他就取到了最新的值
js
data () {
return {
arr: [1, 2, 3, 4]
}
},
methods: {
setArr () {
// 通过数组下标修改的数组数据不是响应式的
// 解决方法:
this.$set(this.arr, 2, 5)
},
setobj:{
this.$set(this.obj,name,'QQ')
}
},