Vue2:Vue的加载流程和IDFF
vue加载流程
1.每一个组件在加载时都会调用vue内部的render函数来把这个组件的tamplate选项的模板解析为一个JS对象
这个对象跟DOM节点对象"长得一模一样",就是为了后来的渲染
Vue.prototype._init = function (options?: Object) { initLifecycle(vm) //1.初始化生命周期的函数 initEvents(vm) //初始化事件 initRender(vm)//生成vnode的模板 callHook(vm, 'beforeCreate')//触发beforeCreate钩子 initInjections(vm) //接受提供者提供的数据 initState(vm)//初始化状态:具体过程在下面函数中--劫持 initProvide(vm) //给别人提供数据 callHook(vm, 'created')//触发created钩子 } export function initState (vm: Component) { vm._watchers = [] const opts = vm.$options if (opts.props) initProps(vm, opts.props) //有属性就初始化属性 if (opts.methods) initMethods(vm, opts.methods)//有方法就初始化方法 if (opts.data) {//有数据源就初始化数据源 initData(vm) } else { observe(vm._data = {}, true /* asRootData */)//没有就监听自带的数据源 } if (opts.computed) initComputed(vm, opts.computed)//有计算属性就初始化计算属性 if (opts.watch && opts.watch !== nativeWatch) { initWatch(vm, opts.watch)//对属性监听 } } //源码分析的结果:属性props>方法methods>数据源data>计算属性computed>对属性监听watch
打包-运行-挂载-每个组件生成的过程{初始化生命周期函数 render执行,把模板字符串翻译成VNode 数据劫持,观测watcher 数据替换 挂载}
如果数据源变了-通知订阅者watcher-异步更新页面-patch函数执行-DIFF-同层比较并打补丁-比较完毕再比较下一层
sameVNode patchVNode UpdataChildren-patchVNode
DIFF算法
什么是DIFF
用 JavaScript 对象结构表示 DOM 树的结构;然后用这个树构建一个真正的 DOM 树,插到文 档当中
当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较(diff),记录两棵树差异
把第二棵树所记录的差异应用到第一棵树所构建的真正的DOM树上(patch),视图就更新了
DIFF算法的过程
当数据发生改变时,订阅者watcher就会调用patch给真实的DOM打补丁
通过sameVnode进行判断,相同则调用patchVnode方法
patchVnode做了以下操作:
1、找到对应的真实dom,称为el
2、如果都有都有文本节点且不相等,将el文本节点设置为Vnode的文本节点
3、如果oldVnode有子节点而VNode没有,则删除el子节点
4、如果oldVnode没有子节点而VNode有,则将VNode的子节点真实化后添加到el
5、如果两者都有子节点,则执行updateChildren函数比较子节点
6、updateChildren主要做了以下操作:
(1)设置新旧VNode的头尾指针
(2)新旧头尾指针进行比较,循环向中间靠拢,根据情况调用patchVnode进行patch重复流程、调用createElem创建一个新节点,从哈希表寻找 key一致的VNode 节点再分情况操作
Vue.prototype._init = function (options?: Object) { initLifecycle(vm) //1.初始化生命周期的函数 initEvents(vm) //初始化事件 initRender(vm)//生成vnode的模板 callHook(vm, 'beforeCreate')//触发beforeCreate钩子 initInjections(vm) //接受提供者提供的数据 initState(vm)//初始化状态:具体过程在下面函数中--劫持 initProvide(vm) //给别人提供数据 callHook(vm, 'created')//触发created钩子 } export function initState (vm: Component) { vm._watchers = [] const opts = vm.$options if (opts.props) initProps(vm, opts.props) //有属性就初始化属性 if (opts.methods) initMethods(vm, opts.methods)//有方法就初始化方法 if (opts.data) {//有数据源就初始化数据源 initData(vm) } else { observe(vm._data = {}, true /* asRootData */)//没有就监听自带的数据源 } if (opts.computed) initComputed(vm, opts.computed)//有计算属性就初始化计算属性 if (opts.watch && opts.watch !== nativeWatch) { initWatch(vm, opts.watch)//对属性监听 } } //源码分析的结果:属性props>方法methods>数据源data>计算属性computed>对属性监听watch