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

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="vue.js"></script>
</head>
<body>
<div id="app">
<h1 ref="info">11</h1>
<child ref="child"></child>
<p v-for="item in items" ref="item">{{item}}</p>
<button @click='show'>Test</button>
</div>
<script>
Vue.component('child',{template:'<h1>I am childComponent</h1>'})
var app = new Vue({
el:'#app',
data:{items:[11,12,13]},
methods:{show:function(){console.log(this.$refs)}} //点击后输出Vue实例的$refs属性
})
</script> </body>
</html>

渲染如下:

点击Test后输出如下:

writer by:大沙漠 QQ:22969969

源码分析


_init初始化的时候会执行initLifecycle()函数,该函数会初始化当前Vue实例的$refs为一个空对象。

挂载的时候首先会将模板解析成一个AST对象,此时会执行processElement()函数,该函数又会执行processRef去解析ref属性,如下:

function processRef (el) {          //第9359行 解析ref属性
var ref = getBindingAttr(el, 'ref'); //尝试获取ref属性
if (ref) { //如果存在
el.ref = ref; //保存到el.ref里面
el.refInFor = checkInFor(el); //执行checkInFor检查是否在v-for循环内,将结果保存到el.refInfor里面
}
}
function checkInFor (el) { //第9605行 检测ref属性是否在v-for里面
var parent = el; //首先将el保存到parent里,这样v-for和ref就可以作用在同一个元素上
while (parent) { //通过检测parent的AST对象是否由for来判断
if (parent.for !== undefined) {
return true //如果在v-for内则返回true
}
parent = parent.parent;
}
return false //否则返回false
}

检测是否在v-for内会影响最后的保存方式,如果在v-for内则最后保存为数组形式,例如例子里的p标签,否则就是非数组,对于h1属性来说,执行到这里后,属性如下:

最后将AST生成render函数的时候会执行genData$2()函数($2是Vue项目build的时候node自动转换的,防止同名),genData$2()会判断是否有ref和refInFor属性,如果有则保存到data属性上(就是render属性对应的参数,这个参数是一个函数,函数的第二个参数),如下:

function genData$2 (el, state) {  //第10274行
var data = '{'; // directives first.
// directives may mutate the el's other properties before they are generated.
var dirs = genDirectives(el, state);
if (dirs) { data += dirs + ','; } // key
if (el.key) {
data += "key:" + (el.key) + ",";
}
// ref
if (el.ref) { //对应ref属性
data += "ref:" + (el.ref) + ",";
}
if (el.refInFor) { //如果组件元素有设置了v-for指令
data += "refInFor:true,";
}
/*略*/
}

最后等到DOM创建后,会执行ref模块的create钩子函数(Vue内部有七个模块,分别对应属性、样式、事件、DOM属性、样式、动画、ref和指令,用于在DOM新增、更新、卸载时执行一些列操作)

ref模块初始化时会执行registerRef函数,如下:

function registerRef (vnode, isRemoval) {     //第5389行 ref的实现函数 vnode:节点对应的VNode,isRemoval:是否移除
var key = vnode.data.ref;
if (!isDef(key)) { return } //如果没有定义ref属性,则直接返回 var vm = vnode.context; //当前的根Vue实例
var ref = vnode.componentInstance || vnode.elm; //优先获取vonde的组件实例(对于组件来说),或者el(该Vnode对应的DOM节点,非组件来说)
var refs = vm.$refs;
if (isRemoval) {
if (Array.isArray(refs[key])) {
remove(refs[key], ref);
} else if (refs[key] === ref) {
refs[key] = undefined;
}
} else { //如果不是移除
if (vnode.data.refInFor) { //当在v-for之内时,则保存为数组形式
if (!Array.isArray(refs[key])) {
refs[key] = [ref];
} else if (refs[key].indexOf(ref) < 0) {
// $flow-disable-line
refs[key].push(ref);
}
} else { //不是在v-for之内时
refs[key] = ref; //直接保存到refs对应的key属性上
}
}
}

ref属性比较简单的,可以方便的引用某个DOM节点或子组件实例,在很多地方用得到,比如Elementui里的表单等

Vue.js 源码分析(十) 基础篇 ref属性详解的更多相关文章

  1. Vue.js 源码分析(九) 基础篇 生命周期详解

    先来看看官网的介绍: 主要有八个生命周期,分别是: beforeCreate.created.beforeMount.mounted.beforeupdate.updated   .beforeDes ...

  2. Vue.js 源码分析(六) 基础篇 计算属性 computed 属性详解

    模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的.在模板中放入太多的逻辑会让模板过重且难以维护,比如: <div id="example">{{ messag ...

  3. Vue.js 源码分析(十三) 基础篇 组件 props属性详解

    父组件通过props属性向子组件传递数据,定义组件的时候可以定义一个props属性,值可以是一个字符串数组或一个对象. 例如: <!DOCTYPE html> <html lang= ...

  4. Vue.js 源码分析(四) 基础篇 响应式原理 data属性

    官网对data属性的介绍如下: 意思就是:data保存着Vue实例里用到的数据,Vue会修改data里的每个属性的访问控制器属性,当访问每个属性时会访问对应的get方法,修改属性时会执行对应的set方 ...

  5. Vue.js 源码分析(三) 基础篇 模板渲染 el、emplate、render属性详解

    Vue有三个属性和模板有关,官网上是这样解释的: el ;提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标 template ;一个字符串模板作为 Vue 实例的标识使用.模板将会 ...

  6. Vue.js 源码分析(二) 基础篇 全局配置

    Vue.config是一个对象,包含Vue的全局配置,可以在启动应用之前修改下列属性,如下: ptionMergeStrategies        ;自定义合并策略的选项silent         ...

  7. Vue.js 源码分析(八) 基础篇 依赖注入 provide/inject组合详解

    先来看看官网的介绍: 简单的说,当组件的引入层次过多,我们的子孙组件想要获取祖先组件的资源,那么怎么办呢,总不能一直取父级往上吧,而且这样代码结构容易混乱.这个就是这对选项要干的事情 provide和 ...

  8. Vue.js 源码分析(七) 基础篇 侦听器 watch属性详解

    先来看看官网的介绍: 官网介绍的很好理解了,也就是监听一个数据的变化,当该数据变化时执行我们的watch方法,watch选项是一个对象,键为需要观察的数据名,值为一个表达式(函数),还可以是一个对象, ...

  9. Vue.js 源码分析(十一) 基础篇 过滤器 filters属性详解

    Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化.过滤器可以用在两个地方:双花括号插值和 v-bind 表达式 (后者从 2.1.0+ 开始支持).过滤器应该被添加在 JavaScrip ...

随机推荐

  1. CSS3特效之转化(transform)和过渡(transition)

    CSS3特效之转化(transform)和过渡(transition) 在对动画深入之前,我们需要先了解它的一些特性,CSS3的转化(transform)和过渡(transition).有人可能会有疑 ...

  2. 有两个CIDR地址块208.128/11和208.130.28/22。是否有那一个地址块包含了另一个地址?如果有,请指出,并说明理由。

    有两个CIDR地址块208.128/11和208.130.28/22.是否有那一个地址块包含了另一个地址?如果有,请指出,并说明理由. 208.128/11的前缀为:11010000 100: 208 ...

  3. react-custom-scrollbars的使用

    react-custom-scrollbars的作用 流畅的本机浏览器滚动 移动设备的本机滚动条 完全可定制 自动隐藏 自动高度 通用(在客户端和服务器上运行) requestAnimationFra ...

  4. CTF必备技能丨Linux Pwn入门教程——stack canary与绕过的思路

    Linux Pwn入门教程系列分享如约而至,本套课程是作者依据i春秋Pwn入门课程中的技术分类,并结合近几年赛事中出现的题目和文章整理出一份相对完整的Linux Pwn教程. 教程仅针对i386/am ...

  5. 四.Windows基础

    系统目录 Windows Program files 用户 Perflogs:是Windows7的日志信息,如磁盘扫描错误信息,删掉可以,但不建议删,删掉反而降低系统速度,perflogs是系统自动生 ...

  6. Oh-My-Zsh的配置与使用

    什么是Shell? 相对于内核来说,Shell是Linux/Unix的一个外壳,它负责外界与Linux内核的交互,接收用户或其他应用程序的命令,然后把这些命令转化成内核能理解的语言,传给内核,内核是真 ...

  7. CornerNet: Detecting Objects as Paired Keypoints

    CornerNet是一种anchor free的目标检测方法,不需要设置anchor,而是通过检测关键点(Keypoints),即目标的左上角(Top-Left Corners)和右下角(Bottom ...

  8. MySQL中建立Oracle中SCOTT数据示例

    1.创建 scott 数据库 CREATE DATABASE scott; 2.创建 scott 数据库中的 dept 表 CREATE TABLE dept( deptno INT UNSIGNED ...

  9. 201871010108-高文利《面向对象程序设计(java)》第十二周学习总结

    项目 内容 这个作业属于哪个课程 <任课教师博客主页链接> https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 <作业链接地址> ht ...

  10. [LeetCode] 896. Monotonic Array 单调数组

    An array is monotonic if it is either monotone increasing or monotone decreasing. An array A is mono ...