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

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

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

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


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

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

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

代码片段来自 2.5.16 版本:

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

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


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

2、获取元素上的 ref 值:

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

  • vnode
  • isRemoval

  1. function registerRef (vnode, isRemoval) {}

直接通过 vnode.data 获取:


  1. var key = vnode.data.ref;

然后获取 $refs

在这之前需要获取 vm

从 vnode 上下文 context 获取


  1. var vm = vnode.context;

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


  1. var refs = vm.$refs;

ref 其实是什么呢?

DOM 节点或组件实例

这里的:

  • componentInstance -- 组件实例
  • elm -- DOM 节点

  1. var ref = vnode.componentInstance || vnode.elm;

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

对应的引用信息是包含 DOM 节点或组件实例的数组


  1. if (vnode.data.refInFor) {}

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

判断方式:Array.isArray


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

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


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

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


  1. refs[key] = ref;

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

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

那我们看看:

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

最开始我们从 _init 开始


  1. Vue.prototype._init = function (options) {
  2. // vm.$mount
  3. if (vm.$options.el) {
  4. vm.$mount(vm.$options.el);
  5. }
  6. }

生成 vnode 最核心的部分:

实例化 VNode


  1. function _createElement (
  2. var vnode;
  3. if (typeof tag === 'string') {
  4. // ...
  5. vnode = new VNode(
  6. config.parsePlatformTagName(tag), data, children,
  7. undefined, undefined, context
  8. );
  9. }
  10. }

我们以如下代码为例:


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

我们的 VNode 如下:

最外层 app 转换的 vnode:


  1. children:[VNode]
  2. data: {
  3. attrs: {
  4. id: "app"
  5. }
  6. }
  7. tag: "div"

子 vnode 如下:


  1. data: {
  2. ref: "imgbox",
  3. attrs: {
  4. src:"https://vuejs.org/images/logo.png",
  5. alt:"Vue logo"
  6. }
  7. }
  8. tag: "img"

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


  1. var ref = {
  2. create: function create (_, vnode) {
  3. registerRef(vnode);
  4. }
  5. }

在函数 invokeCreateHooks 调用 create

注意两点:

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


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

后面会提到:hooks


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

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


  1. function createPatchFunction (backend) {
  2. var cbs = {};
  3. var modules = backend.modules;
  4. for (i = 0; i < hooks.length; ++i) {
  5. cbs[hooks[i]] = [];
  6. for (j = 0; j < modules.length; ++j) {
  7. // ...
  8. cbs[hooks[i]].push(modules[j][hooks[i]]);
  9. }
  10. }
  11. }

那谁调用了 createPatchFunction 函数呢:


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

我们发现 baseModules 关联了 ref


  1. var baseModules = [
  2. ref,
  3. directives
  4. ]

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

ref 与 $refs 如何关联的更多相关文章

  1. vue.js中ref及$refs的使用及讲解

    关于ref和$refs的用法及讲解,vue.js中文社区( https://cn.vuejs.org/v2/api/#ref )是这么讲解的: ref 被用来给元素或子组件注册引用信息,引用信息将会注 ...

  2. vue中的 ref 和 $refs

    如图,ref 被用来给元素或子组件注册引用信息.引用信息将会注册在父组件的 $refs 对象上.如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素:如果用在子组件上,引用就指向组件实例: ...

  3. vue的ref与$refs

    一. ref使用在父组件上 父组件html: <information ref='information'></information> import information ...

  4. ref、refs使用的注意事项

    ref是被用来给元素或子组件注册引用信息.引用信息将注册在父组件的 $refs 对象身上.如果在普通的DOM元素身上使用,引用指向就是DOM元素:如果用在子组件身上,引用就是指向组件实例. 当v-fo ...

  5. Vue 获取dom元素之 ref 和 $refs 详解

    一.$refs 一个对象,持有ref注册过的所有元素或子组件.(注册过的 ref 的集合) 二.ref 被用来给元素或子组件注册引用信息.若用在dom元素上,引用指向的就是dom元素:若用在子组件上, ...

  6. 理解Vue中的ref和$refs

    参考博客:https://www.cnblogs.com/xumqfaith/p/7743387.html

  7. Vue 中的 ref $refs

    ref 被用来给DOM元素或子组件注册引用信息.引用信息会根据父组件的 $refs 对象进行注册.如果在普通的DOM元素上使用,引用信息就是元素; 如果用在子组件上,引用信息就是组件实例 注意:只要想 ...

  8. vue特殊属性 key ref slot

    1.key 当使用key时,必须设置兄弟元素唯一的key,当key排列顺序变化时,兄弟元素会重新排列,而当key的值变化时,这个元素会被重新渲染. 有相同父元素的子元素必须有独特的 key.重复的 k ...

  9. oracle ref游标

    Oracle 系列:REF Cursor 在上文  Oracle 系列:Cursor  (参见:http://blog.csdn.net/qfs_v/archive/2008/05/06/240479 ...

随机推荐

  1. mybatis如何在控制台打印执行的sql语句

    log4j.rootLogger=DEBUG, Console #Console log4j.appender.Console=org.apache.log4j.ConsoleAppender log ...

  2. Goldbach

    Description: Goldbach's conjecture is one of the oldest and best-known unsolved problems in number t ...

  3. POJ2560 Freckles

    Time Limit: 1000MS   Memory Limit: 65536KB   64bit IO Format: %lld & %llu Description In an epis ...

  4. POJ 1182 食物链 [并查集 带权并查集 开拓思路]

    传送门 P - 食物链 Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u Submit  ...

  5. HDu1241 DFS搜索

    #include<iostream> #include<cstring> using namespace std; int a[105][105]; int d[8][2]={ ...

  6. 安装破解版的webstorne

    参考以下链接:https://www.cnblogs.com/cui-cui/p/8507435.html

  7. npm start 修改启动端口的不同方式

    antd的启动配置文件基于package.json文件,配合roadhog使用时,启动配置是: "scripts": { "start": "road ...

  8. TCP No-Delay

    Nagle 算法 由于TCP中包头的大小是固定的,所以在数据(Payload)大小很小的时候IP报文的有效传输率是很低的,Nagle算法就是将多个即将发送的小段的用户数据,缓存并合并成一个大段数据时, ...

  9. T1013 求先序排列 codevs

    http://codevs.cn/problem/1013/  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解  查看运行结果     题目描述 Descr ...

  10. luogu P1149 火柴棒等式

    题目描述 给你n根火柴棍,你可以拼出多少个形如“A+B=C”的等式?等式中的A.B.C是用火柴棍拼出的整数(若该数非零,则最高位不能是0).用火柴棍拼数字0-9的拼法如图所示: 注意: 加号与等号各自 ...