首页 > 作文

Vue.js 源码分析(十五) 指令篇 v

更新时间:2023-04-06 08:21:12 阅读: 评论:0

指令是vue.js模板中最常用的一项功能,它带有前缀v-,比如上面说的v-if、v-html、v-pre等。指令的主要职责就是当其表达式的值改变时,相应的将某些行为应用到dom上,先介绍v-bind指令

v-bind用于动态地绑定一个或多个特性,或一个组件 prop 到表达式。

例如:

<!doctype html><html lang="en"><head>    <meta chart="utf-8">    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>    <title>document</title>    </head><body>    <div id="app"><a v-bind:href="href">链接</a></div>    <script>    vue.config.productiontip=fal;    vue.config.devtools=fal;    var app = new vue({        el:'#app',        data:{href:"http://www.baidu.com"}    })    </script> </body></html>

渲染为:

当我们点击整个超链接时将跳转到http://www.baidu.com,如果在控制台输入app.href=”http://www.taobao.com”时:

点击按钮后就跳转到淘宝了

源码分析

以上面的例子为例,vue内部将dom解析成ast对象的时候会执行par()函数,该函数解析到a节点时会执行到proceslement()函数,该函数先将key、ref、插槽、class和style解析完后就会执行processattrs()函数,如下:

function processattrs (el) {    //第9526行  对剩余的属性进行分析  var list = el.attrslist;  var i, l, name, rawname, value, modifiers, isprop;   for (i = 0, l = list.length; i < l; i++) {              //遍历每个属性    name = rawname = list[i].name;     value = list[i].value;    if (dirre.test(name)) {                                //如果该属性以v-、@或:开头,表示这是vue内部指令      // mark element as dynamic      el.hasbindings = true;      // modifiers       modifiers = parmodifiers(name);                     //获取修饰符,比如:{native: true,prevent: true}      if (modifiers) {        name = name.replace(modifierre, '');      }      if (bindre.test(name)) { // v-bind                      //bindrd等于/^:|^v-bind:/ ,即该属性是v-bind指令时 例如:<a :href="url">你好</a>        name = name.replace(bindre, '');                          //去掉指令特性,获取特性名,比如 href        value = parfilters(value);                              //对一些表达式做解析,例如{a|func1|func2}        isprop = fal;                                           //是否绑定到dom对象上        if (modifiers) {          if (modifiers.prop) {                                   //如果有修饰符            isprop = true;            name = camelize(name);            if (name === 'innerhtml') { name = 'innerhtml'; }          }          if (modifiers.camel) {            name = camelize(name);          }          if (modifiers.sync) {            addhandler(              el,              ("update:" + (camelize(name))),              genassignmentcode(value, "$event")            );          }        }        if (isprop || (          !el.component && platformmustuprop(el.tag, el.attrsmap.type, name)    //如果isprop为true        )) {                                                                            //则调用addprop()          addprop(el, name, value);        } el {          addattr(el, name, value);                                               //否则调用addattr()        }      } el if (onre.test(name)) { // v-on                     //onre等于/^@|^v-on:/,即该属性是v-on指令时        name = name.replace(onre, '');        addhandler(el, name, value, modifiers, fal, warn$2);      } el { // normal directives                             //普通指令        name = name.replace(dirre, '');        // par arg        var argmatch = name.match(argre);        var arg = argmatch && argmatch[1];        if (arg) {          name = name.slice(0, -(arg.length + 1));        }        adddirective(el, name, rawname, value, arg, modifiers);        if ("development" !== 'production' && name === 'model') {          checkforaliasmodel(el, value);        }      }    } el {      /*略*/    }  }}

addattr()函数用于在ast对象上新增一个attrs属性,如下:

function addattr (el, name, value) {    //第6550行   (el.attrs || (el.attrs = [])).push({ name: name, value: value });     //将{name: name,value: value}保存到el.attrs里面  el.plain = fal;                                                      //修正el.plain为fal}

例子里执行到这里时对应的ast对象为:

执行generate()函数获取data$2时会判断是否有attrs属性,如果有则将属性保存到attrs上,例子里的实例渲染后render函数等于:

  if (el.attrs) {     //第10306行    data += "attrs:{" + (genprops(el.attrs)) + "},";  }

genprops用于拼凑对应的值,如下:

function genprops (props) {     //第10537行 拼凑ast对象的属性或dom属性用的  var res = '';     for (var i = 0; i < props.length; i++) {    //遍历prps    var prop = props[i];                         //对应的值    /* istanbul ignore if */    {      res += "\"" + (prop.name) + "\":" + (transformspecialnewlines(prop.value)) + ",";   //拼凑字符串    }  }  return res.slice(0, -1)}

例子执行到这里渲染的render函数等于:

with(this) {
return _c('div', {
attrs: {
"id": "app"
}
},
[_c('a', {
attrs: {
"href": href
}
},
[_v("链接")])])
}

这样当该函数执行的时候就会触发vue实例的href属性,此时就会将渲染watcher作为href属性的订阅者了,当href修改时就会触发渲染watcher的重新渲染了。

最后当a标签整个dom元素生成之后会触发attrs模块的create事件去设置href特性,如下:

function updateattrs (oldvnode, vnode) {      //第6294行 更新attrs  var opts = vnode.componentoptions;                                      //获取vnode.componentoptions(组件才有)  if (isdef(opts) && opts.ctor.options.inheritattrs === fal) {    return  }  if (isundef(oldvnode.data.attrs) && isundef(vnode.data.attrs)) {        //如果在oldvnode和vnode上都没有定义attrs属性    return                                                                     //则直接返回,不做处理  }  var key, cur, old;  var elm = vnode.elm;  var oldattrs = oldvnode.data.attrs || {};  var attrs = vnode.data.attrs || {};                             //新vnode的attrs属性  // clone obrved objects, as the ur probably wants to mutate it  if (isdef(attrs.__ob__)) {    attrs = vnode.data.attrs = extend({}, attrs);  }  for (key in attrs) {                                            //遍历新vnode的每个attrs    cur = attrs[key];    old = oldattrs[key];    if (old !== cur) {      tattr(elm, key, cur);                                     //则调用tattr设置属性    }  }  // #4391: in ie9, tting type can ret value for input[type=radio]  // #6666: ie/edge forces progress value down to 1 before tting a max  /* istanbul ignore if */  if ((isie || idge) && attrs.value !== oldattrs.value) {       //ie9的特殊情况    tattr(elm, 'value', attrs.value);  }  for (key in oldattrs) {    if (isundef(attrs[key])) {     房地产营销策划方案 if (isxlink(key)) {        elm.removeattributens(xlinkns, getxlinkprop(key));      } el if (!inumeratedattr(key)) {        elm.removeattribute(key);      }    }  }}function tattr (el, key, value) {         //设置el元素的key属性为value  if (el.tagname.indexof('-') > -1) {            //如果el的标签名里含有-    batattr(el, key, value);   } el if (isbooleanattr(key)) {                //如果key是布尔类型的变量(比如:disabled、lected)    // t attribute for blank value    // e.g. <option disabled>lect one</option>    if (isfalsyattrvalue(value)) {      el.removeattribute(key);    } el {      // te梁祝故事chnically allowfullscreen is a boolean attribute for <iframe>,      // but flash expects a value of "true" when ud on <embed清代帝王> tag      value = key === 'allowfullscreen' && el.tagname === 'embed'        ? 'true'        : key;      el.tattribute(key, value);    }  } el if (inumeratedattr(key)) {             //如果key是这三个之一:contenteditable,draggable,spellcheck    el.tattribute(key, isfalsyattrvalue(value) || value === 'fal' ? 'fal' : 'true');  } el if (isxlink(key)中国学历) {    if (isfalsyattrvalue(value)) {      el.removeattributens(xlinkns, getxlinkprop(key));    } el {      el.tattributens(xlinkns, key, value);    }  } el {                                          //不满足上述的情况就直接调用batattr设置属性    batattr(el, key, value);  }}function batattr (el, key, value) {         //设置el的key属性为value  if (isfalsyattrvalue(value))招商广告 {                  //如果value是null或fal    el.removeattribute(key);                       //则删除属性  } el {     // #7138: ie10 & 11 fires input event when tting placeholder on    // <textarea>... block the first input event and remove the blocker    // immediately.    /* istanbul ignore if */    if (       isie && !isie9 &&      el.tagname === 'textarea' &&      key === 'placeholder' && !el.__ieph    ) {                                         特殊情况       var blocker = function (e) {        e.stopimmediatepropagation();        el.removeeventlistener('input', blocker);      };      el.addeventlistener('input', blocker);      // $flow-disable-line      el.__ieph = true; /* ie placeholder patched */    }    el.tattribute(key, value);                    //直接调用原生domapi tattribute设置属性  }}

本文发布于:2023-04-06 08:20:52,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/zuowen/4056ad1fe7b49099435fbeac08357a39.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

本文word下载地址:Vue.js 源码分析(十五) 指令篇 v.doc

本文 PDF 下载地址:Vue.js 源码分析(十五) 指令篇 v.pdf

上一篇:PHP 中的类
下一篇:返回列表
标签:属性   函数   指令   对象
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图