数据劫持
vue2中采用的是Object.defineProperty方法,重写对象属性的getter和setter函数。vue3采用的是Proxy。
发布订阅者模式
对象的每个属性有一个Dep实例,专门存储依赖。
依赖收集:
某个组件在进行compile(指令解析、初始化视图时),因为js是单线程,所以当前只会有一个组件在compile。
-
这个组件会将自己赋值给全局变量target。
-
获取数据时,会触发该属性的getter函数,getter函数会将当前target添加到自己的dep中收集起来,完成依赖收集。
-
这个组件compile完成后,会释放target,target = null。
发布更新
数据变化时,发布通知,所有订阅者更新:
-
当我们修改一个数据时,会触发该属性的setter函数。
-
setter函数中会调用dep中的notify方法,notify中会遍历所有依赖,调用他们的update方法,使所有的依赖(组件)去更新。
render函数和virtual DOM
从模板到真实DOM:
首先我们的template模板,会被vue-loader(compliler)编译成render()函数,render()函数返回的是virtual DOM,然后Vue基于virtual DOM生成真实DOM。
DOM更新过程:
生成virtual DOM的过程实质上是调用render()函数,而渲染函数和data的属性有依赖关系。渲染函数在调用过程中就会进行一个依赖收集,一旦这些数据发生变化,就会再次调用render()函数,生成新的virtual DOM。然后新旧virtual DOM会进行比较、区分,最终将少量的更改应用到真实DOM中。
virtual DOM
首先真实DOM属性值太多,操作起来是非常耗时的,而virtual DOM的节点实质是js对象,所以对比和操作都是在js层面完成的,速度会快很多。
{ tag: 'div', data: { attrs: {}, ...}, children:[] }
// virtual DOM节点,不难看出,结构很简单,主要就三个属性,标签、属性、子节点。