前言
时隔半年,再写一篇关于vue源码的总结文章,期间刚好工作了半年(也刚好用了半年vue),也陆陆续续地看了一些别人写的源码分析。这里再记下对vue的认识。
vue 框架运行的三个重要阶段
- 配置项校验合并阶段
参见Vue源码分析(3)—选项合并过程mergeOptions - 初始化响应式系统
参见Vue源码分析(4)—实例的初始化过程 - 组件挂载、依赖收集、页面更新(Virtual DOM Diff)
参见Vue源码分析(5)—观察者收集、组件渲染挂载过程
vue 框架的三大核心内容
- 响应式系统
data中的对象obj会被观测(observe),结果就是obj的每个可枚举属性都被配置了一个dep属性,专门用来收集各种watcher实例(通过Object.defineProperty重写了属性的存取器函数办到的)。当组件开始挂载时(vm.$mount(vm.options.el)),组件的render函数被调用,从而触发了属性的get函数,该属性对应的dep就会收集当前活跃的watcher实例(也即render watcher),挂载完毕后页面的初次渲染就完成了。当data中的数据发生变化时会触发对应属性的set函数,set函数会调用该属性对应的dep中的wathcer实例的run方法,该方法最终经过Diff算法算出页面最小变动部分,从而实现页面更新。 - 模板编译系统
通过正则手段,将vue语法格式的html字符串解析成AST,最终通过字符串拼接的方式产生render和renderStatic函数 - 批量更新 & Diff 算法
页面初次渲染后,如果data中的数据发生变化,比如a,b两个属性发生变化,并不是a属性变化时更新一下页面,b属性变化时再更新一下页面,而是a,b两个属性都变化以后只更新一次页面(前提是ab的变化不是异步的),这就是批量更新的意思。实现的原理是内部实现了nextTick函数,触发属性的set函数时,会将该属性收集的watcher放入队列中,等此次事件循环结束后统一在下次循环时依次执行(本质上执行watcher.run方法);
Diff算法是按层级比较的,因此时间复杂度为o(n),效率上是很高效的(暂未深入研究)