经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » HTML/CSS » HTML5 » 查看文章
Vue.js 源码分析(十) ref属性详解
来源:cnblogs  作者:大沙漠  时间:2019/6/25 10:19:17  对本文有异议

用法


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

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Document</title>
  6. <script src="vue.js"></script>
  7. </head>
  8. <body>
  9. <div id="app">
  10. <h1 ref="info">11</h1>
  11. <child ref="child"></child>
  12. <p v-for="item in items" ref="item">{{item}}</p>
  13. <button @click='show'>Test</button>
  14. </div>
  15. <script>
  16. Vue.component('child',{template:'<h1>I am childComponent</h1>'})
  17. debugger
  18. var app = new Vue({
  19. el:'#app',
  20. data:{items:[11,12,13]},
  21. methods:{show:function(){console.log(this.$refs)}} //点击后输出Vue实例的$refs属性
  22. })
  23. </script>
  24.  
  25. </body>
  26. </html>

渲染如下:

点击Test后输出如下:

 

源码分析


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

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

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

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

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

  1. function genData$2 (el, state) { //第10274行
  2. var data = '{';
  3. // directives first.
  4. // directives may mutate the el's other properties before they are generated.
  5. var dirs = genDirectives(el, state);
  6. if (dirs) { data += dirs + ','; }
  7. // key
  8. if (el.key) {
  9. data += "key:" + (el.key) + ",";
  10. }
  11. // ref
  12. if (el.ref) { //对应ref属性
  13. data += "ref:" + (el.ref) + ",";
  14. }
  15. if (el.refInFor) { //如果组件元素有设置了v-for指令
  16. data += "refInFor:true,";
  17. }
  18. /**/
  19. }

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

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

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

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

 

原文链接:http://www.cnblogs.com/greatdesert/p/11075698.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号