vue源码解析之Directives原理

1,430 阅读3分钟

什么时候用

当我们的methods中存在操作DOM/BOM的逻辑的时候,就该思考是否可以抽象成一个自定义指令。

开始

  1. 模板上指令怎么解析;
  2. 怎么获取到设置的指令钩子;
  3. 内部怎么调用钩子函数;

指令解析

<div v-test v-test2></div>

该指令会被解析的渲染函数为:

with(this) {    
    return _c('div', {        
        directives: [{            
            name: "test",            
            rawName: "v-test"
        },{
            name: "test2",
            rawName: "v-test2"
        }]
    })
}

获取指令钩子

  1. 获取所有的旧节点的指令和新节点的指令;
  2. 在获取指令的时候把对应的钩子函数绑定到指令上;

调用钩子

钩子函数中的参数,除了el之外,其他的参数都应该是只读的,切勿进行修改。如果需要在钩子函数之间共享数据,建议通过元素的dataset来进行。

指令的钩子函数都会在updateDirectives方法中执行,会根据不同场景来执行下面5个钩子函数

bind

只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置

inserted

inserted是在DOM插入父节点之后才触发的(仅保证父节点存在,但不一定已被插入文档中),而处理inserted是在DOM插入之前,所以这里不可能直接触发,只能是先保存起来,等到节点被插入之后再触发。所以,inserted 分为收集和执行两个步骤:

收集

  1. 创建数组dirsWithInsert;
  2. 如果只在新节点中包含的指令,并且有inserted,则加入dirsWithInsert队列;
  3. 所有指令收集完毕则再执行inserted钩子函数;
执行

  1. inserted 钩子是所有节点都插入完毕之后才触发的,而不是插入一个节点就触发一次;
  2. 遍历收集到的dirsWithInsert指令集合,并执行对应的inserted钩子函数;

update

所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新。

componentUpdated

指令所在组件的 VNode 及其子 VNode 全部更新后调用。这个钩子和 inserted 差不多,只是执行的流程不一样。componentUpdated 钩子是更新一个节点就马上执行的,更新一个节点的意思是包括其内部的子节点的。

inserted和componentUpdated差异
  1. inserted是所有节点,包括其子节点全部插入后,统一执行inserted钩子;
  2. componentUpdated钩子是更新一个节点就马上执行的;

unbind

只调用一次,指令与元素解绑时调用

vue系列课程

最近会陆续的对vue进行源码分析,一系列课程如下:

state系列

  1. props原理
  2. methods原理
  3. data原理
  4. computed原理
  5. watch原理

lifecycle系列

  1. 生命周期原理

event系列

  1. event原理

render系列

  1. render原理

inject/provide系列

  1. inject/provide原理

plugins系列

  1. vue-router原理
  2. Vue Router 那些事
  3. Vuex你应该知道的事
  4. vue源码解析之vuex原理
  5. Vue自定义插件

组件系列

  1. keep-alive原理
  2. Vue 单文件组件
  3. Vue组件间通信
  4. vue虚拟列表

指令系列

  1. Vue自定义指令
  2. vue源码解析之Directives原理

算法系列

  1. diff原理
  2. Vue编译器源码分析

异步任务

  1. vue源码解析之NextTick原理

其他

  1. vue单元测试
  2. Vue轮播组件
  3. 你不知道的vue那些事
  4. vue技巧大解密
  5. 面试-高级前端之VUE数据响应式实现