首页 > 作文

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

更新时间:2023-04-03 03:04:22 阅读: 评论:0

v-show的作用是将表达式值转换为布尔值,根据该布尔值的真假来显示/隐藏切换元素,它是通过切换元素的display这个css属性值来实现的,例如:

<!doctype html><html lang="en"><head>    <meta chart="utf-8">    <title>document</title>    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script></head><body>    <div id="d"><p v-show="isshow">hello vue!</p></div>     <script>        vue.config.productiontip=fal;        vue.config.devtools=fal;        var app = new vue({el:'#d',data:{isshow:true}})    </script></body></html>

渲染结果为:

当我们在修改isshow为fal时:

页面里的hello vue!就隐藏部件了,我们查看dom结构如下:

可以看到vue是通过修改display这个css属性来隐藏元素的

源码分析

在解析模板将dom转换成ast对象的时候会执行processattrs()函数,如下:

function processattrs (el) {                     //解析vue的属性  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);      if (modifiers) {        name = name.replace(modifierre, '');      }      if (bindre.test(name)) { // v-bind                          //bindrd等于/^:|^v-bind:/ ,即该属性是v-bind指令时        /*v-bind的分支*/      } el if (onre.test(name)) { // v-on        /*v-on的分支*/      } el { // normal directives        name = name.replace(dirre, '');                         //去掉指令前缀,比如v-show执行后等于show        // par arg        var argmatch = name.match(argre);        var arg = argmatch && argmatch[1];        if (arg) {          name = name.slice(0, -(arg.lefun的形容词ngth + 1));        }        adddirective(el, name, rawname,2021年开学第一课感想 value, arg, modifiers); //执行adddirective给el增加一个directives属性        if ("development" !== 'production' && name === 'model') {          checkforaliasmodel(el, value);        }      }    } el {      /*非vue指令的分支*/    }  }}

adddirective会给ast对象上增加一个directives属性保存指令信息,如下:

function adddirective (                         //第6561行 指令相关,给el这个ast对象增加一个directives属性,值为该指令的信息  el,  name,  rawname,  value,  arg,  modifiers) {  (el.directives || (el.directives = [])).push({ name: name, rawname: rawname, value: value, arg: arg, modifiers: modifiers });  el.plain = fal;}

例子里的p元素执行到这里时对应的ast对象如下:

接下来在generate生成rendre函数的时候,会执行gendirectives()函数,将ast转换成一个render函数,如下:

with(this){return _c('div',{attrs:{"id":"d"}},[北京居住证办理条件_c('p',{directives:[{name:"show",rawname:"v-show",value:(isshow),expression:"isshow"}]},[_v("hello vue!")])])}

最后等渲染完成后会执行directives模块的create钩子函数,如下:

var directives = {                 //第6173行 directives模块   create: updatedirectives,             //创建dom后的钩子  update: updatedirectives,  destroy: function unbinddirectives (vnode) {    updatedirectives(vnode, emptynode);  }}fu形容花开nction updatedirectives (oldvnode, vnode) {         //第6181行   oldvnode:旧的vnode,更新时才有 vnode:新的vnode  if (oldvnode.data.directives || vnode.data.directives) {    _update(oldvnode, vnode);  }}function _update (oldvnode, vnode) {                 //第6187行 初始化/更新指令  var iscreate = oldvnode === emptynode;                                                     //是否为初始化  var isdestroy = vnode === emptynode;  var olddirs = normalizedirectives$1(oldvnode.data.directives, oldvnode.context);            var newdirs = normalizedirectives$1(vnode.data.directives, vnode.context);                 //调用normalizedirectives$1()函数规范化参数1,返回格式:{v-show:{name: "show", rawname: "v-show", value: true, expression: "ok", modifiers: {…}, …}}       var dirswithinrt = [];  var dirswithpostpatch = [];  var key, olddir, dir;  for (key in newdirs) {                                     //遍历newdirs    olddir = olddirs[key];                                         //oldvnode上的key指令信息    dir = newdirs[key];                                            //vnode上的key指令信息  刘禹锡的代表作  if (!olddir) {                                                 //如果olddir不存在,即是新增指令      // new directive, bind      callhook$1(dir, 'bind', vnode, oldvnode);                     //调用callhook$1()函数,参数2为bind,即执行v-show模块的bint函数      if (dir.def && dir.def.inrted) {        dirswithinrt.push(dir);      }    } el {      // existing directive, update      dir.oldvalue = olddir.value;      callhook$1(dir, 'update', vnode, oldvnode);      if (dir.def && dir.def.componentupdated) {        dirswithpostpatch.push(dir);      }    }  }  /*以下略*/}

normalizedirectives$1会调用resolveast()函数从vue.options.directives里获取v-show指令的信息如下:

function normalizedirectives$1 (         //第6249行      规范化dirs    dirs,  vm) {  var res = object.create(null);             //存储最后的结果  if (!dirs) {                                 //如果用户没有定义指令,则直接返回空对象    // $flow-disable-line    return res  }  var i, dir;  for (i = 0; i < dirs.length; i++) {             ///遍历dirs    dir = dirs[i];    if (!dir.modifiers) {                                                     //如果没有修饰符,则重置dir.modifiers为空对象      // $flow-disable-line      dir.modifiers = emptymodifiers;    }               res[getrawdirname(dir)] = dir;                                             //将dir保存到res里面,键名为原始的指令名    dir.def = resolveast(vm.$options, 'directives', dir.name, true);         //调用resolveast获取该指令的信息,是一个对象,保存到res的def属性里面  }  // $flow-disable-line  return res}

resolveast是获取资源用的,当我们定义了组件、过滤器、指令时,都通过该函数获取对应的信息,之前组件和过滤里介绍了,这里不说了

回到_update函数,最后调用callhook$1()函数,参数2为bind,该函数如下:

function callhook$1 (dir, hook, vnode, oldvnode, isdestroy) {         //第6276行 执行指令的某个回调函数 dir:指令信息,  var fn = dir.def && dir.def[hook];                                     //尝试获取钩子函数  if (fn) {    try {      fn(vnode.elm, dir, vnode, oldvnode, isdestroy);                         //执行钩子函数,参数依次为绑定的元素、dir对象、新的vnode,老的vnode    } catch (e) {      handleerror(e, vnode.context, ("directive " + (dir.name) + " " + hook + " hook"));    }  }}

v-show指令的信息如下:

var show = {                 //第8082行 v-show指令的信息  bind: function bind (el, ref, vnode) {         //初次绑定时执行    var value = ref.value;    vnode = locatenode(vnode);    var transition$$1 = vnode.data && vnode.data.transition;         //尝试获取transition,如果v-show绑定的标签外层套了一个transition则会把信息保存到该对象里 这是transition的组件分支,可先忽略     var originaldisplay = el.__voriginaldisplay =                      //保存最初的display属性      el.style.display === 'none' ? '' : el.style.display;    if (value && transition$$1) {                                     //如果transition$$1存在的话      vnode.data.show = true;      enter(vnode, function () {        el.style.display = originaldisplay;      });    } el {      el.style.display = value ? originaldisplay : 'none';             //否则直接根据value的值是否可以转换为1来设置el.style.display属性    }  },  update: function update (el, ref, vnode) {    /*更新时的逻辑*/  },  unbind: function unbind (    el,    binding,    vnode,    oldvnode,    isdestroy  ) {    /*卸载时的逻辑*/  }}

v-show的流程就是这样的,注意,v-show不支持<template>元素,也不支持v-el。

本文发布于:2023-04-03 03:04:19,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/zuowen/569f09bb192e5f04be303ad6003b5b96.html

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

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

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

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