• ref 与 $refs 如何关联


    先问大家一个简单的问题:

    还有人记得 jquery 里面的 data 方法是如何让 DOM 节点绑定对应的数据对象的吗

    有时候我们做节点关联设计的思路其实有一点类似,但是在 vue 里面多了很多概念,比如:

    1、vnode: 如何生成的,包含子父关系、属性 data
    2、内置的 ref 对象的 create 如何注册
    3、生命周期:解析到根节点之后获取 outerHTML 再一步一步解析子元素


    用惯 vue 的人都会很熟悉地:

    使用 ref 来注册引用信息,再通过 $refs 对象就可以做关联

    但是我们看看它们是如何关联上的呢?

    代码片段来自 2.5.16 版本:

    1、需要初始化 $refs,默认是一个空对象

    我们看到在函数 initLifecycle 上会往 vm 上设置一个 key 为 $refs 值为一个对象

    
    function initLifecycle (vm) {
      vm.$refs = {};
    }
    

    2、获取元素上的 ref 值:

    在函数 registerRef 上,它接受 2 个参数:

    • vnode
    • isRemoval
    
    function registerRef (vnode, isRemoval) {}
    

    直接通过 vnode.data 获取:

    
    var key = vnode.data.ref;
    

    然后获取 $refs

    在这之前需要获取 vm

    从 vnode 上下文 context 获取
    
    var vm = vnode.context;
    

    然后很简单的就是 vm.$refs

    
    var refs = vm.$refs;
    

    ref 其实是什么呢?

    DOM 节点或组件实例

    这里的:

    • componentInstance -- 组件实例
    • elm -- DOM 节点
    
    var ref = vnode.componentInstance || vnode.elm;
    

    这里需要处理一下 v-for 一起用的情况,官网也提过:

    对应的引用信息是包含 DOM 节点或组件实例的数组
    
    if (vnode.data.refInFor) {}
    

    情况一:如果不是数组格式,强制转换一下,外层套一个数组

    判断方式:Array.isArray

    
    if (!Array.isArray(refs[key])) {
      refs[key] = [ref];
    }
    

    情况二:看数组里面是否存在当前这个 ref,如果不存在,push 进去

    
    if (refs[key].indexOf(ref) < 0) {
      refs[key].push(ref);
    }
    

    如果不是和 v-for 一起用:直接设置对象的 key 和 value:

    
    refs[key] = ref;
    

    最后一个问题,官网提到了:

    ref 注册时间 -- 因为 ref 本身是作为渲染结果被创建的,在初始渲染的时候你不能访问它们 - 它们还不存在

    那我们看看:

    1、它到底是在什么时机绑定的
    2、vnode 是如何产生的

    最开始我们从 _init 开始

    
    Vue.prototype._init = function (options) {
      // vm.$mount
      if (vm.$options.el) {
          vm.$mount(vm.$options.el);
        }
    }
    

    生成 vnode 最核心的部分:

    实例化 VNode

    
    function _createElement (
      var vnode;
      if (typeof tag === 'string') {
        // ...
        vnode = new VNode(
            config.parsePlatformTagName(tag), data, children,
            undefined, undefined, context
          );
      }
    }
    

    我们以如下代码为例:

    
    <div id="app">
        <img ref="imgbox" src="https://vuejs.org/images/logo.png" alt="Vue logo">
      </div>
    

    我们的 VNode 如下:

    最外层 app 转换的 vnode:

    
    children:[VNode]
    data: {
      attrs: {
        id: "app"
      }
    }
    tag: "div"
    

    子 vnode 如下:

    
    data: {
      ref: "imgbox",
      attrs: {
        src:"https://vuejs.org/images/logo.png",
        alt:"Vue logo"
      }
    }
    tag: "img"
    

    内置了一个 ref 对象,里面有 create 函数,调用了 registerRef

    
    var ref = {
      create: function create (_, vnode) {
        registerRef(vnode);
      }
    }
    

    在函数 invokeCreateHooks 调用 create

    注意两点:

    1、cbs 是什么?
    2、create又是什么,和 ref 对象的 create 有什么关系

    
    function invokeCreateHooks (vnode, insertedVnodeQueue) {
      for (var i$1 = 0; i$1 < cbs.create.length; ++i$1) {
          cbs.create[i$1](emptyNode, vnode);
        }
    }
    

    后面会提到:hooks

    
    var hooks = ['create', 'activate', 'update', 'remove', 'destroy'];
    

    核心部分:createPatchFunction,往 cbs 里面放置对应的函数

    
    function createPatchFunction (backend) {
      var cbs = {};
    
      var modules = backend.modules;
    
      for (i = 0; i < hooks.length; ++i) {
        cbs[hooks[i]] = [];
        for (j = 0; j < modules.length; ++j) {
          // ...
          cbs[hooks[i]].push(modules[j][hooks[i]]);
        }
      }
    }
    

    那谁调用了 createPatchFunction 函数呢:

    
    var modules = platformModules.concat(baseModules);
    
    var patch = createPatchFunction({ nodeOps: nodeOps, modules: modules });
    

    我们发现 baseModules 关联了 ref

    
    var baseModules = [
      ref,
      directives
    ]
    

    来源:https://segmentfault.com/a/1190000016323531

  • 相关阅读:
    典型用户及场景分析
    使用搜狗输入法个人感受
    第二期站立会议10
    寻找“水王”
    第二期站立会议9
    第二期站立会议8
    第二期站立会议7
    第二期站立会议6
    第二期站立会议5
    第二期站立会议4
  • 原文地址:https://www.cnblogs.com/qixidi/p/10143723.html
Copyright © 2020-2023  润新知