Vue首次渲染过程
首先进行Vue的初始化,也就是初始化Vue的实例成员以及静态成员。
当初始化结束之后,开始调用构造函数,在构造函数中调用this._init(),这个方法相当于我们整个Vue的入口。
在_init()中最终调用了this.mount(),第一个mount(),这个$mount()的核心作用是帮我们把模板编译成render函数,但它首先会判断一下我们当前是否传入了render选项,如果没有传入的话,它会去获取我们的template选项,如果template选项也没有的话,他会把el中的内容作为我们的模板,然后把模板编译成render函数,它是通过compileToFunctions()函数,帮我们把模板编译成render函数的,当把render函数编译好之后,它会把render函数存在我们的options.render中。
那接下来会调用runtime/index.js中的mount()中重新获取el。
接下来调用mountComponent(),mountComponent()是在src/core/instance/lifecycle.js中定义的,在mountComponent()中,首先会判断render选项,如果没有但是传入了模板,并且当前是开发环境的话会发送警告,警告运行时版本不支持编译器。
接下来会触发beforeMount这个生命周期中的钩子函数,也就是开始挂载之前。
然后定义了updateComponent(),在这个方法中,定义了_render和_update,_render的作用是生成虚拟DOM,_update的作用是将虚拟DOM转换成真实DOM,并且挂载到页面上来。
再接下来就是创建Watcher对象,在创建Watcher时,传递了updateComponent这个函数,这个函数最终是在Watcher内部调用的。在Watcher创建完之后还调用了get方法,在get方法中,会调用updateComponent()。
然后触发了生命周期的钩子函数mounted,挂载结束,最终返回Vue实例。
响应式处理过程
initState() --> initData() --> observe()
observe(value)
位置:src/core/observer/index.js 功能: 判断value是否是对象,如果不是对象直接返回 判断value对象是否有__ob__,如果有直接返回 如果没有,创建observer对象 返回observer对象
Observer
位置:src/core/observer/index.js 功能: 给value对象定义不可枚举的__ob__属性,记录当前的observer对象 数组的响应式处理 对象的响应式处理,调用walk方法
defineReactIve
位置:src/core/observer/index.js 功能: 为每一个属性创建dep对象 如果当前属性的值是对象,调用observe 定义getter 收集依赖 返回属性的值 定义setter 保存新值 如果新值是对象,调用observe 派发更新(发送通知),调用dep.notify()
收集依赖
在watcher对象的get方法中调用pushTarget记录Dep.target属性 访问data中的成员的时候收集依赖,defineReactive的getter中收集依赖 把属性对应的watcher对象添加到dep的subs数组中 给childOb收集依赖,目的是子对象添加和删除成员时发送通知
Watcher
dep.notify()在调用watcher对象的update()方法 queueWatcher()判断watcher是否被处理,如果没有的话添加到queue队列中,并调用flushScheduleQueue() flushScheduleQueue() 触发beforeUpdate钩子函数 调用watcher.run(): run() --> get() --> getter() --> updateComponent 清空上一次的依赖 触发actived的钩子函数 触发updated钩子函数
虚拟dom的作用
避免直接操作DOM,提高开发效率 作为一个中间层可以跨平台 虚拟DOM不一定可以提高性能 首次渲染的时候会增加开销 复杂视图情况下提升渲染性能
什么是虚拟dom
虚拟DOM就是使用JavaScript对象描述真实DOM Vue中的虚拟DOM借鉴Snabbdom,并添加了Vue的特性,例如指令和组件机制
虚拟 DOM 中 Key 的作用和好处
- 以便它能够跟踪每个节点的身份,在进行比较的时候,会基于 key 的变化重新排列元素顺序。从而重用和重新排序现有元素,并且会移除 key 不存在的元素。方便让 vnode 在 diff 的过程中找到对应的节点,然后成功复用.
- 可以减少 dom 的操作,减少 diff 和渲染所需要的时间,提升了性能。
Vue 中模板编译的过程
- 模板编译的主要目的是将模板(template)转换为渲染函数(render)
- 编译的入口函数:调用 compileToFunctions( template, {}, this) , 返回 { render,staticRenderFns },作用:把 template 转换成 render 函数
createCompiler( baseOptions ):
a:定义 compile(template,option)函数
b:生成 compileToFunctions
c:返回 { compile,compileToFunctions }
createCompilerCreator(function baseCompile(){}):
a:传入了 baseCompile( template,options ) 函数
b:baseCompile:核心函数:解析 parse;优化 optimize;生成 generate;
c:返回 createCompiler 函数