写文章不容易,点个赞呗兄弟
专一 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工做原理,源码版助于了解内部详情,让咱们一块儿学习吧
研究基于 Vue版本 【2.5.17】
若是你以为排版难看,请点击 下面连接 或者 拉到 下面关注公众号也能够吧node
今天是除夕啦,你们新年快乐!身体健康!2019多多开花,耶,嗨起来!dom
言归正传!函数
我相信应该你们应该都使用过 Directive 指令,有时为了可以直接操做DOM,而指令中最重要的莫过因而 钩子函数了,指令一共有五个钩子函数,他们不会在不一样的阶段触发,文档也已经说明性能
固然了,其实你只要了解它是何时触发的,就彻底能够用在项目。可是咱们是不会知足于此的,我要知道他是怎么触发的,怎么调用到我设置的钩子的学习
今天,咱们就来简单说一下这几个钩子都是怎么被调用的spa
你能相信我写 Directive 花了一个星期啊,不是有多难,而是我不知道怎么下手写啊,根本不知道怎么描述会简单好了解,吐血3d
首先,Vue 在绑定了指令的DOM 建立以后,插入页面以前,对一些DOM 自己的事件或者属性等进行处理。code
其中,就包含对本DOM的全部指令进行处理component
怎么处理呢?每个钩子函数都不同,因此咱们会分不一样钩子说明
首先,处理时,Vue 要判断哪些指令是新的仍是旧的
因此须要比较 旧节点上的指令 和 新节点上的指令
好比 新指令比旧指令 多了一个指令 ,以下
// 新指令 newDir 以下 newDir={ "v-test":{ name: "test", rawName: "v-test" }, "v-test2":{ name:"test2" rawName:"v-test2" } } // 旧指令 oldDir 以下,少了一个 v-test2 oldDir={ "v-test":{ name: "test", rawName: "v-test" } }
若是是新指令
遍历新指令对象时,当 'v-test2' 指令不存在 旧指令对象中,则表示这个是新指令,须要初始化
一、bind
遍历遇到新指令时,直接执行 bind 钩子函数,并传入参数
for(i in newDir){ var dir = newDir[i] if( !oldDir[i]){ dir.bind(....参数) } }
二、inserted
按文档的说明,咱们就知道,inserted 是在节点插入父节点调用
而全部节点的全部钩子,会放在同一时间一块儿处理,并非插入一个节点,就执行一个节点的 inserted 钩子
inserted 分为 保存 和 执行 两个步骤
由于inserted 须要在 节点插入以后才执行,而如今处理是在 节点插入以前,因此只能先保存起来,用于后面执行。
简单实现以下
// 一、使用一个数组 保存 本 DOM 的 全部新指令的 inserted 钩子 var dirInserted = [] for(i in newDir){ var dir = newDir[i] if( !oldDir[i]){ dir.bind(....参数) dirInserted.push(dir.inserted) } } // 二、新建一个函数,专门遍历这个数组,逐个执行 inserted 钩子 var callback = function(){ for(var i=0;i=dirInserted.length;i++){ dirInserted[i](....参数) } } // 三、 把 callback 保存进当前节点的一个地方,为了后面使用 dom.insert = callback // 四、把 全部含有 callback 的节点,也放到一个数组 var insertedVnodeQueue=[] if( 存在inserted 的 dom ){ insertedVnodeQueue.push( dom ) } // 五、当节点插入后,开始遍历insertedVnodeQueue for (var i = 0; i <insertedVnodeQueue.length; ++i) { insertedVnodeQueue[i].insert(); }
为了验证 inserted 钩子 并非插入一个节点,就执行一次,我特意在 插入节点的函数后面打印一句话,因而能够看到以下的打印顺序
bind---> SPAN 插入DOM span bind---> P 插入DOM p bind---> DIV 插入DOM div inserted---> SPAN inserted---> P inserted---> DIV
若是是旧指令
遍历新指令对象时,当 v-test 指令也存在旧指令对象中,则表示这个是旧指令,须要更新
一、update
碰到旧指令,会直接执行 update 钩子函数,并传入参数
for(i in newDir){ var dir = newDir[i] if( !oldDir[i]){ dir.bind(....参数) }else{ dir.update(...参数) } }
二、componentUpdated
componentUpdated 的保存方式 和 inserted 差很少,可是执行方式却不同。
哎哟,这个钩子是,更新一个节点,就立刻执行该节点钩子的喔。跟 inserted 彻底不同喔,虽然我也不懂为何
我也在源码内更新 DOM 后加了一句打印,而后咱们看下执行顺序
update---> DIV update---> SPAN 完成更新DOM span componentUpdated---> SPAN update---> P 完成更新DOM p componentUpdated---> P 完成更新DOM div componentUpdated---> DIV
三、unbind
当 新指令 比 旧指令少了,好比下面这样
// 旧指令 { "v-test":{ name: "test", rawName: "v-test" }, "v-test2":{ name:"test2" rawName:"v-test2" } } // 新指令 { "v-test":{ name: "test", rawName: "v-test" } }
那么 v-test2 指令被去掉了,这时确定会触发 unbind 钩子
unbind 钩子也是直接调用的,没有那么多转来转去的逻辑幺蛾子,可是须要两个判断条件
一、不是新节点。刚刚建立的指令,指令确定都是新的,就不必往下走,浪费性能
二、某个旧指令 不存在 新指令对象中。证实这个指令已经被移除
if( 不是新节点 ){ for(i in oldDir){ var dir = oldDir[i] if( !newDir[i]){ dir.unbind(....参数) } } }