Skip to content
On this page

什么是虚拟 DOM

  • 是对真实 DOM 的引射,就是一个对象

为什么要有虚拟 DOM

  1. 真实 DOM 上有一堆的属性和方法,直接操作真实的 DOM 每次都会导致重绘和回流,所以性能差; 操作虚拟 DOM 不存在性能问题,因为他是等数据全部更新完毕之后,只会更新真实 DOM 树需要改变的地方,只有一次重绘和回流
  2. 组件初始化的时候创建一个虚拟 DOM 树,数据更新时生成一个新的虚拟 DOM 树,利用 diff 算法广度遍历对新旧 DOM 树一层一层的进行比较
  3. diff 算法
    • 如果是元素变了,删除元素,创建新的元素
    • 如果属性或内容变了,修改属性和内容
    • 使用 v-for 遍历的时候
      • 没有 key 的时候或者 Key 是索引的时候,diff 算法会采用就地复用的原则,再顺序上位置是同一个索引会被认为是同一个元素,使用改变数据顺序的方法的时候,就会导致不需要更新的元素也会更新
      • 当给 key 的值是唯一标识的时候 ,它通过diff算法进行比较的时候能够通过key值最快速的去找到哪个变化的Dom元素从而对它进行修改
  4. 虚拟 DOM 的作用:可以实现高效更新(数据变了的时候视图更新效率更高),可以实现跨平台(一套代码可以生成不同的平台的最终代码)

数据响应式的原理

  1. 数据响应式就是数据变了,视图跟着变 利用 Object.defineProperty 数据劫持和观察者模式来实现的
  2. Object.defineProperty 里面有一个 get 和 set 方法。 get 可以返回被劫持的属性的值,set 可以修改被劫持的属性的值,在数据初始化的时候把 data 里面的数据进行转换,每个数据创建一个 Dep(被观察者)
  3. 对模板进行编译 (compiler) 提取里面所有需要数据的地方变成 watcher (观察者),然后把 watcher(观察者) 加入到对应的 Dep(被观察者) 的观察者列表中
  4. 当 data 中某个属性变化的时候,由于被劫持了,所以 vue 内部是知道的,就会调用对应的 dep(被观察者) 去通知观察者列表中所有的观察者 然后观察者去更新视图
  5. 存在的问题:
    新增属性 删除属性界面不会更新
    直接通过下标修改数组界面不会更新
    原因: 读取数据会调用getter()修改数据调用setter() 所以新增和删除属性object.difineProperty是监测不到的
  6. 解决办法:
  • 使用this.$set(要操作的数据,要修改的下标(或要增加的属性),修改(或新增的是什么)成什么)或者用Vue.set()这个API
    删除的话使用this.$delete()或者Vue.delete()API
  • 修改数组下标还可以使用数组的splice()方法
  1. 不响应又响应的情况是:比如再修改数组下标或给对象新增属性 后面又操作了其他数据 此时是可以拿到更新后的数据的 因为后面操作了其他的数据当数据发生变化 组件就会更新 组件更新 页面也会更新 他就取到了最新的值
js
data () {
    return {
      arr: [1, 2, 3, 4]
    }
  },
  methods: {
    setArr () {
      // 通过数组下标修改的数组数据不是响应式的
      // 解决方法:
      this.$set(this.arr, 2, 5)
    },
    setobj:{
      this.$set(this.obj,name,'QQ')
    }
  },

Vue3数据响应式