先问大家一个简单的问题:
还有人记得 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 ]
作者:dailyvuejs
链接:https://www.jianshu.com/p/d33738b78a71