Vue.js源码分析(十七)指令篇v-if、v-el-if和v-el指令详解

更新时间:2023-07-03 01:47:59 阅读: 评论:0

Vue.js源码分析(⼗七)指令篇v-if、v-el-if和v-el指令详
v-if 指令⽤于条件性地渲染⼀块内容。这块内容只会在指令的表达式返回true值的时候被渲染。
v-el-if,顾名思义,充当 v-if 的“el-if 块”,可以连续使⽤:
也可以使⽤ v-el 指令来表⽰ v-if 的“el 块”:
挺好理解的,就和⼤多数的语⾔的if()....el if()...el逻辑语句是⼀样的,例如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta chart="UTF-8">
<title>Document</title>
<script src="cdn.jsdelivr/npm/vue@2.5.16/dist/vue.js"></script>
</head>
<body>
<script>
</script>
<div id="app">
平安夜快乐英文怎么说<p v-if="no<0">n⼩于0</p>
<p v-el-if="no==0">no等于0</p>
<p v-el>no⼤于0</p>
</div>
<script>var app = new Vue({el:'#app',data:{no:2}})</script>
</body>
</html>
渲染为:
腾飞教育
有两个注意点:
  v-el和v-el-if 必须紧跟在带 v-if 或者 v-el-if 的元素之后,⼀会⼉将源码的时候会讲到为什么
  因为 v-if 是⼀个指令,所以必须将它添加到⼀个元素上。但是如果想切换多个元素呢?此时可以把⼀个 <template> 元素当做不可见的包裹元素,
源码分析
爱疯4s图片
Vue内部会把v-if、v-el、v-el-if解析称为⼀个三元运算符,如果有多个v-el,则三元运算符内再嵌套⼀个三元运算符,以例⼦⾥的为例:
解析模板解析到<p v-if="no<0">n⼩于0</p>这个DOM元素时会执⾏到processIf()函数
function processIf (el) {              //第9402⾏解析v-if指令
var exp = getAndRemoveAttr(el, 'v-if');  //获取表达式,例如:"no<0"
if (exp) {                                  //如果存在v-if属性
el.if = exp;                                  //增加if属性
addIfCondition(el, {                          //调⽤addIfCondition()函数给el增加⼀个ifConditions属性,值是⼀个对象,其中 exp表⽰当前v-if的值,block是当前AST对象的引⽤(⼀会⼉给v-el和v-el-if⽤的)
exp: exp,
block: el
});
} el {                                  //如果不存在v-if属性
if (getAndRemoveAttr(el, 'v-el') != null) {    //如果存在el命令,则在el.el上增加⼀个el属性
el.el = true;
}
var elif = getAndRemoveAttr(el, 'v-el-if'); //如果存在v-el-if指令,则添加elif属性
if (elif) {
el.elif = elif;
}
}
}
function addIfCondition (el, condition) { //第9453⾏增加⼀个ifConditions属性,
if (!el.ifConditions) {
el.ifConditions = [];                    //如果ifConditions属性不存在则初始化为⼀个空数组
}
el.ifConditions.push(condition);            //将参数condition这个对象push进来
}
对于v-if节点只是增加⼀个if和ifConditions属性,对于<p v-if="no<0">n⼩于0</p>来说,对应的AST对象增加的属性如下:
解析模板时,对于v-el和v-el-if来说,并没有把当前对应的AST对象加到AST树中,⽽是把⾃⼰对应的AST对象添加到最近的v-if的ifConditions⾥,代码如下:
if (currentParent && !element.forbidden) {      //第9223⾏如果当前对象不是根对象,且不是style和text/javascript类型script标签
if (element.elif || element.el) {            //如果有elif或el指令存在(设置了v-el或v-elif指令)
processIfConditions(element, currentParent);      //则调⽤processIfConditions()函数
} el if (element.slotScope) { // scoped slot    //如果element是作⽤域插槽
currentParent.plain = fal;
var name = element.slotTarget || '"default"';(currentParent.scopedSlots || (currentParent.scopedSlots = {}))[name] = element;
} el {
currentParent.children.push(element);
element.parent = currentParent;
}两星期
}
processIfConditions会在之前的AST节点,也就是v-if的AST节点的ifConditions上把当前的ast对象添加进去,如下:
function processIfConditions (el, parent) {      //第9421⾏解析v-el、v-el-if指令
var prev = findPrevElement(parent.children);        //调⽤findPrevElement获取el之前的AST对象(只查找普通元素AST) if (prev && prev.if) {                                //如果prev存在,且它含有v-if指令
addIfCondition(prev, {                                  //则调⽤addIfCondition给prev的ifConditions添加⼀条语句
exp: el.elif,
block: el
});
} el {
warn$2(
"v-" + (el.elif ? ('el-if="' + el.elif + '"') : 'el') + " " +
"ud on element <" + (el.tag) + "> without corresponding v-if."
);
}
}
function findPrevElement (children) {          //第9436⾏查找children前⼀个⽂本AST对象
var i = children.length;
while (i--) {                                  //遍历children,从后开始
if (children[i].type === 1) {                    //如果是普通节点
return children[i]                                //则直接返回该元素
} el {
if ("development" !== 'production' && children[i].text !== ' ') {  //开发模式下,如果该节点不是普通节点,则报错
warn$2(
"text \"" + (children[i].im()) + "\" between v-if and v-el(-if) " +
"will be ignored."
);
}
children.pop();
}
}
}
执⾏完后整个AST对象树如下:
接下来执⾏generate⽣成rendre函数时时发现有有if属性就执⾏genIf()函数:
function genIf (                //第10205⾏  //渲染v-if指令
shoot是什么意思
el,
state,
altGen,
terminatealtEmpty
) {
el.ifProcesd = true; // avoid recursion                                  //避免递归
return genIfConditions(el.ifConditions.slice(), state, altGen, altEmpty)    //调⽤genIfConditions函数
}
gatfunction genIfConditions (      //第10215⾏拼凑if表达式 conditions:⽐如:[{exp: "ok", block: {…}}]
托福听力加试算分吗conditions,
state,
altGen,
altEmpty
) {
if (!conditions.length) {            //如果conditions不存在
return altEmpty || '_e()'            //则直接返回altEmpty
}
var condition = conditions.shift();    //获取内容,⽐如:{exp: "no<0", block: {…}}
打气什么意思if (p) {                  //拼凑三元运算符
return ("(" + (p) + ")?" + (genTernaryExp(condition.block)) + ":" + (genIfConditions(conditions, state, altGen, altEmpty)))  } el {
return ("" + (genTernaryExp(condition.block)))
}
// v-if with v-once should generate code like (a)?_m(0):_m(1)
function genTernaryExp (el) {        //再次调⽤genElement()函数
return altGen
altGen(el, state)
: el.once
ad chinagenOnce(el, state)
: genElement(el, state)
}
}
最后渲染的render函数为:
_c('div',{attrs:{"id":"app"}},[(no<0)?_c('p',[_v("n⼩于0")]):(no==0)?_c('p',[_v("no等于0")]):_c('p',[_v("no⼤于0")])])
其中
(no<0)?_c('p',[_v("n⼩于0")]):(no==0)?_c('p',[_v("no等于0")]):_c('p',[_v("no⼤于0")])
就是对应的例⼦⾥的v-if、v-el、v-el-if结构了

本文发布于:2023-07-03 01:47:59,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/90/165334.html

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

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