Vue中提供了v-if 和v-show 指令来方便我们控制模版的显示逻辑,本文我们主要是通过简单的源码来分析两者的区别。
一:使用方式
<div v-if="show">test</div>
<div v-show="show">test</div>
二:实现机制
v-if 在条件变量为false的时候,不生成dom,v-show 则肯定存在dom,只不过dom的display的值是none
我们先来看看v-if的底层实现
#读取v-if v-else v-else-if 生对应的条件属性存起来供其他函数来使用
function processIf (el) {
var exp = getAndRemoveAttr(el, 'v-if');
if (exp) {
el.if = exp;
addIfCondition(el, {
exp: exp,
block: el
});
} else {
if (getAndRemoveAttr(el, 'v-else') != null) {
el.else = true;
}
var elseif = getAndRemoveAttr(el, 'v-else-if');
if (elseif) {
el.elseif = elseif;
}
}
}
#根据上面的条件属性生成render函数字符串
function genIfConditions (
conditions,
state,
altGen,
altEmpty
) {
if (!conditions.length) {
return altEmpty || '_e()'
}
var condition = conditions.shift();
if (condition.exp) {
// 重点在这里,生成了一个三元表达式
return ("(" + (condition.exp) + ")?" + (genTernaryExp(condition.block)) + ":" + (genIfConditions(conditions, state, altGen, altEmpty)))
} else {
return ("" + (genTernaryExp(condition.block)))
}
// v-if with v-once should generate code like (a)?_m(0):_m(1)
function genTernaryExp (el) {// 处理v-once 只响应第一次渲染的情况
return altGen
? altGen(el, state)
: el.once
? genOnce(el, state)
: genElement(el, state)
}
}
可以看到生成的render函数表达式里,会判断show变量是否为true,是的话才会调用_c来创建dom。
再来看v-show
var show = {
bind: function bind (el, ref, vnode) {
var value = ref.value;
vnode = locateNode(vnode);
var transition$$1 = vnode.data && vnode.data.transition;
var originalDisplay = el.__vOriginalDisplay =
el.style.display === 'none' ? '' : el.style.display;
if (value && transition$$1) {
vnode.data.show = true;
enter(vnode, function () {
el.style.display = originalDisplay;
});
} else {
el.style.display = value ? originalDisplay : 'none'; // 在这里控制style的display属性
}
},
update: function update (el, ref, vnode) {
var value = ref.value;
var oldValue = ref.oldValue;
/* istanbul ignore if */
if (!value === !oldValue) { return }
vnode = locateNode(vnode);
var transition$$1 = vnode.data && vnode.data.transition;
if (transition$$1) {
vnode.data.show = true;
if (value) {
enter(vnode, function () {
el.style.display = el.__vOriginalDisplay;
});
} else {
leave(vnode, function () {
el.style.display = 'none';
});
}
} else {
el.style.display = value ? el.__vOriginalDisplay : 'none';
}
},
unbind: function unbind (
el,
binding,
vnode,
oldVnode,
isDestroy
) {
if (!isDestroy) {
el.style.display = el.__vOriginalDisplay;
}
}
};
var platformDirectives = {// 平台的两个内置指令v-model 和 v-show
model: directive,
show: show
};
v-show 是vue核心的内置指令之一(还有一个是v-model)指令的机制我们择日再解读。
我们可以看到v-show 指令处理的时候是通过控制dom的style的display来控制的。也就是说dom是一值存在的。
三:总结
从表现上看,v-if 和v-show都可以控制dom的显示和隐藏。
v-if 是惰性的,当条件是false的时候不渲染dom,而v-show 无论如何都渲染dom。
v-if 切换开销大,v-show 初始渲染开销大。所以对于频繁切换的组件,建议使用v-show。
v-if 还有一些配合使用的指令比如v-else-if v-else。
v-show 不支持在template上绑定,也不支持和v-else配合使用