资讯专栏INFORMATION COLUMN

[vue 源码系列] ref 与 $refs 如何关联

gougoujiang / 2881人阅读

摘要:先问大家一个简单的问题还有人记得里面的方法是如何让节点绑定对应的数据对象的吗有时候我们做节点关联设计的思路其实有一点类似,但是在里面多了很多概念,比如如何生成的,包含子父关系属性内置的对象的如何注册生命周期解析到根节点之后获取再一步一步解析

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

还有人记得 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
      );
  }
}

我们以如下代码为例:

Vue logo

我们的 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://www.ucloud.cn/yun/97559.html

相关文章

  • [vuejs 踩坑实战系列] 路由场景下父子组件的生命周期顺序来个刨根问底

    摘要:大家中秋假期快乐,假期分享一些原理设计文章给大家原创不易,欢迎转发,一起学习凌晨写的,不容易哈,收藏或者点个赞吧在常见的单页应用中,我们都会有一个根文件,里面放置一个然后配置路由来切换很多人在子父组件嵌套关系下的生命周期钩子函数如何应用, 大家中秋假期快乐,假期分享一些原理设计文章给大家 原创不易,欢迎转发,一起学习(凌晨写的,不容易哈,收藏或者点个赞吧) 在常见的单页应用中,我们都...

    FreeZinG 评论0 收藏0
  • vue全家桶制作一个精致的美团项目

    摘要:的组件化功能可谓是它的一大亮点,通过将页面上某一组件的代码放入一个的文件中进行管理可以大大提高代码的维护性。项目中未做移动端适配,在不同屏幕手机上打开,可能用户体验会差些 一、项目展示: showImg(https://user-gold-cdn.xitu.io/2018/5/18/1637183ad14a696a?w=372&h=791&f=gif&s=2408442); 注意:如果...

    NeverSayNever 评论0 收藏0
  • 人人都能懂的Vue源码系列—08—initLifecycle

    摘要:主要是通过为我们属性添加一些自定义的行为。方法用来初始化一些生命周期相关的属性,以及为等属性赋值,来看源码。名称说明指定已创建的实例之父实例,在两者之间建立父子关系。一个对象,持有已注册过的所有子组件。 上篇文章,我们讲了vm._renderProxy相关的内容。主要是通过Proxy为我们vm属性添加一些自定义的行为。今天我们回到init方法中,为大家讲解initLifecycle。i...

    Cristalven 评论0 收藏0
  • 剖析 React 源码:先热个身

    摘要:我们先来看下这个函数的一些神奇用法对于上述代码,也就是函数来说返回值是。不管你第二个参数的函数返回值是几维嵌套数组,函数都能帮你摊平到一维数组,并且每次遍历后返回的数组中的元素个数代表了同一个节点需要复制几次。这是我的 React 源码解读课的第一篇文章,首先来说说为啥要写这个系列文章: 现在工作中基本都用 React 了,由此想了解下内部原理 市面上 Vue 的源码解读数不胜数,但是反观...

    sean 评论0 收藏0

发表评论

0条评论

gougoujiang

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<