什么时候用
当我们的methods中存在操作DOM/BOM的逻辑的时候,就该思考是否可以抽象成一个自定义指令。
开始
- 模板上指令怎么解析;
- 怎么获取到设置的指令钩子;
- 内部怎么调用钩子函数;
指令解析
<div v-test v-test2></div>
该指令会被解析的渲染函数为:
with(this) {
return _c('div', {
directives: [{
name: "test",
rawName: "v-test"
},{
name: "test2",
rawName: "v-test2"
}]
})
}
获取指令钩子
- 获取所有的旧节点的指令和新节点的指令;
- 在获取指令的时候把对应的钩子函数绑定到指令上;
调用钩子
钩子函数中的参数,除了el之外,其他的参数都应该是只读的,切勿进行修改。如果需要在钩子函数之间共享数据,建议通过元素的dataset来进行。
指令的钩子函数都会在updateDirectives方法中执行,会根据不同场景来执行下面5个钩子函数
bind
只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置
inserted
inserted是在DOM插入父节点之后才触发的(仅保证父节点存在,但不一定已被插入文档中),而处理inserted是在DOM插入之前,所以这里不可能直接触发,只能是先保存起来,等到节点被插入之后再触发。所以,inserted 分为收集和执行两个步骤:
收集
- 创建数组dirsWithInsert;
- 如果只在新节点中包含的指令,并且有inserted,则加入dirsWithInsert队列;
- 所有指令收集完毕则再执行inserted钩子函数;
执行
- inserted 钩子是所有节点都插入完毕之后才触发的,而不是插入一个节点就触发一次;
- 遍历收集到的dirsWithInsert指令集合,并执行对应的inserted钩子函数;
update
所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新。
componentUpdated
指令所在组件的 VNode 及其子 VNode 全部更新后调用。这个钩子和 inserted 差不多,只是执行的流程不一样。componentUpdated 钩子是更新一个节点就马上执行的,更新一个节点的意思是包括其内部的子节点的。
inserted和componentUpdated差异
- inserted是所有节点,包括其子节点全部插入后,统一执行inserted钩子;
- componentUpdated钩子是更新一个节点就马上执行的;
unbind
只调用一次,指令与元素解绑时调用
vue系列课程
最近会陆续的对vue进行源码分析,一系列课程如下: