美文网首页
vue源码分析(二十八)Vue之自定义指令directives

vue源码分析(二十八)Vue之自定义指令directives

作者: vue爱好者 | 来源:发表于2020-04-21 20:53 被阅读0次

    一个指令定义对象可以提供如下几个钩子函数 (均为可选):
    bindinsertedupdatecomponentUpdatedunbind
    具体的说明请参考vue官网的 自定义指令说明文档。

    首先是解析vue实例的directives选项

    /**
     * 将原始函数指令规范化为对象格式。
     */
    function normalizeDirectives (options: Object) {
      const dirs = options.directives
      if (dirs) {
        for (const key in dirs) {
          const def = dirs[key]
         // 如果指令的key值是一个函数的话,那就是'bind'和'update'公用一个处理函数
          if (typeof def === 'function') {
            dirs[key] = { bind: def, update: def }
          }
        }
      }
    }
    

    我们打开文件src/core/vdom/modules/directives.js

    首先vue指令的声明分全局定义局部定义
    1、全局定义:Vue.directive
    2、局部定义:directives: {}
    3、指令不能含有大写字母

    /* @flow */
    
    import { emptyNode } from 'core/vdom/patch'
    import { resolveAsset, handleError } from 'core/util/index'
    import { mergeVNodeHook } from 'core/vdom/helpers/index'
    
    export default {
      create: updateDirectives, 
      update: updateDirectives,
      destroy: function unbindDirectives (vnode: VNodeWithData) {
        updateDirectives(vnode, emptyNode)
      }
    }
    // 更新指令,只要新的虚拟节点或者旧的虚拟节点存在一个,就会调用_update
    function updateDirectives (oldVnode: VNodeWithData, vnode: VNodeWithData) {
      if (oldVnode.data.directives || vnode.data.directives) {
        _update(oldVnode, vnode)
      }
    }
    // 新建和更新都是在这个函数里面
    function _update (oldVnode, vnode) {
      const isCreate = oldVnode === emptyNode
      const isDestroy = vnode === emptyNode
      // 新的指令
      const oldDirs = normalizeDirectives(oldVnode.data.directives, oldVnode.context)
      // 旧的指令
      const newDirs = normalizeDirectives(vnode.data.directives, vnode.context)
    
      const dirsWithInsert = []
      const dirsWithPostpatch = []
    
      let key, oldDir, dir
      for (key in newDirs) {
        oldDir = oldDirs[key]
        dir = newDirs[key]
       // 如果旧的指令不存在就调用'bind'钩子函数,否则就调用'update'钩子函数。
       // bind:只调用一次,指令第一次绑定到元素时调用。
        if (!oldDir) {
          // 调用'bind'钩子函数
          callHook(dir, 'bind', vnode, oldVnode) 
          if (dir.def && dir.def.inserted) {
            dirsWithInsert.push(dir)
          }
        } else {
          // existing directive, update
          dir.oldValue = oldDir.value
          dir.oldArg = oldDir.arg
          // 数据更新 =》虚拟节点更新=》指令的更新=》调用'update'钩子函数
         /*
          update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改 
            变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见 
          下)。
        */
          callHook(dir, 'update', vnode, oldVnode)
          if (dir.def && dir.def.componentUpdated) {
            dirsWithPostpatch.push(dir)
          }
        }
      }
     // 如果提供了'inserted'钩子函数,就是调用'inserted'钩子
      if (dirsWithInsert.length) {
        const callInsert = () => {
          for (let i = 0; i < dirsWithInsert.length; i++) {
            callHook(dirsWithInsert[i], 'inserted', vnode, oldVnode)
          }
        }
        // 创建阶段,调用‘inserted’钩子
        if (isCreate) {
          mergeVNodeHook(vnode, 'insert', callInsert)
        } else {
          callInsert()
        }
      }
      // 指令所在组件的 VNode 及其子 VNode 全部更新后调用。
      if (dirsWithPostpatch.length) {
        mergeVNodeHook(vnode, 'postpatch', () => {
          for (let i = 0; i < dirsWithPostpatch.length; i++) {
            callHook(dirsWithPostpatch[i], 'componentUpdated', vnode, oldVnode)
          }
        })
      }
     // unbind:只调用一次,指令与元素解绑时调用。
      if (!isCreate) {
        for (key in oldDirs) {
          if (!newDirs[key]) {
            // no longer present, unbind
            callHook(oldDirs[key], 'unbind', oldVnode, oldVnode, isDestroy)
          }
        }
      }
    }
    

    指令的解析是从createElm创建节点函数来调用的,我们可以看看整个调用序列图:

    image.png
    const isCreate = oldVnode === emptyNode
    const isDestroy = vnode === emptyNode
    

    可以看到上面定义了两个变量,isCreateisDestroy,通过字面意思我们就可以知道他的用途了。
    1、旧的虚拟节点oldVnode是一个空的节点就是新增 (isCreate )
    2、新的虚拟节点vnode是一个空的节点就是销毁 (isDestroy )

    相关文章

      网友评论

          本文标题:vue源码分析(二十八)Vue之自定义指令directives

          本文链接:https://www.haomeiwen.com/subject/pvssuhtx.html