这里为你详细讲解“vue中v-if和v-show使用区别源码分析”的完整攻略。
1. v-if 和 v-show 的使用区别
在Vue中,v-if和v-show的主要区别在于初始渲染时是否会被渲染出来。
-
v-if:如果表达式的值为false,则元素根本不会被渲染到页面中,只有在表达式的值为true时,元素才会被渲染到页面中。
-
v-show:无论表达式的值是true还是false,都会被渲染到页面中,只是在页面中的display属性值不一样(true时为"display: block;",false时为"display: none;")。
下面我们将采用示例来详细说明两者的区别。
首先,我们在html模板中定义两个按钮“Button 1”和“Button 2”,并分别通过v-if和v-show来控制它们的显示和隐藏:
<template>
<div>
<button v-if="showButton1">Button 1</button>
<button v-show="showButton2">Button 2</button>
</div>
</template>
接下来,我们在data中定义showButton1和showButton2两个变量,并在methods中定义toggleShow方法来切换变量的值:
<script>
export default {
data() {
return {
showButton1: true,
showButton2: true
}
},
methods: {
toggleShow() {
this.showButton1 = !this.showButton1
this.showButton2 = !this.showButton2
}
}
}
</script>
现在,我们来看一下,当页面初次渲染时,v-if和v-show的表现形式之间的区别:
v-if:
如果showButton1的值为true,则按钮1会显示在页面中;
如果showButton1的值为false,则按钮1不会显示在页面中。
v-show:
如果showButton2的值为true,则显示按钮2,并且按钮2在页面中的样式为"display: block;";
如果showButton2的值为false,则显示按钮2,并且按钮2在页面中的样式为"display: none;"。
接下来,我们在页面中添加一个“Toggle”按钮,并将toggleShow方法绑定到该按钮的click事件,测试它们的表现:
<template>
<div>
<button v-if="showButton1">Button 1</button>
<button v-show="showButton2">Button 2</button>
<button @click="toggleShow">Toggle</button>
</div>
</template>
当我们单击“Toggle”按钮时,toggleShow方法将被调用,showButton1和showButton2的值将会被反转。
此时,v-if和v-show的表现形式之间的区别将更明显:
-
v-if:当showButton1的值从true变成false时,按钮1将从页面中消失;当showButton1的值从false变成true时,按钮1将重新出现在页面中。
-
v-show:当showButton2的值从true变成false时,按钮2仍然存在于页面中,只是在页面中的display属性值被修改为"display: none;",按钮不可见;当showButton2的值从false变成true时,按钮2同样存在于页面中,只是display属性值被修改为"display: block;",按钮可见。
2. v-if 和 v-show 的源码分析
接下来,我们来分析一下v-if和v-show的源代码实现。
首先,我们来看一下v-if的实现方式:
// 工具函数
function addVIF(node, directive) {
const exp = directive.expression
const parent = node.parent
const trueBranch = node.clone()
const falseBranch = new VNode('#comment', '', [], node.text, node.__ownerArray, node.__ukey)
trueBranch.props = trueBranch.props || {}
trueBranch.props['v-backup-props'] = node.props
trueBranch.directives = trueBranch.directives || []
trueBranch.directives.push({
value: exp,
arg: undefined,
modifiers: {},
name: 'show'
})
if (exp) {
const branch = new VNode('#branch', '', [trueBranch])
exp && directive.cb(branch, parent, directive)
} else {
const branch = new VNode('#branch', '', [falseBranch])
directive.cb(branch, parent, directive)
}
}
Vue.prototype._lifecycleHooks.push('attached', function attached () {
let i, l
if (this._isAttached && !this._isDestroyed) {
for (i = 0, l = this.$children.length; i < l; i++) {
this.$children[i].$callHook('attached')
}
}
})
// 指令注册
Vue.directive('if', {
"terminal": true,
"priority": 1000,
"transclude": 'element',
"update": function updateFn (value) {
var _this = this
if (!value) {
if (!this._block) {
this._block = this.build()
this._start = new VNode('#comment', '', [], '', undefined, this._block.__ukey)
this._end = new VNode('#comment', '', [], '', undefined, this._block.__ukey)
replace(this.el, this._block, this._start)
append(this._block, this._end)
addVIF(this._block, this)
}
} else {
if (this._block) {
remove(this._block)
this._block = null
}
}
this._isBlockDestroyed = !value
this._fragmentFactory = value
},
"build": function build () {
var Frag = Vue.FragmentFactory.clone(),
children = Frag.parse(this._raw)
this.compiled = children
this.transcluded = true
return Frag.create(children)
},
"unbind": function unbindFn () {
if (this._absorb) return
if (this._block && this._isBlockDestroyed !== false) {
this._block.linker.destroy()
this._block.__v_trans = null
}
}
})
我们来解读一下上面的源代码:
-
在addVIF函数中,我们可以看到,当v-if表达式的值为false时,工具函数addVIF将创建一个注释型#comment的虚拟节点,用于替换原有的节点。
-
在Vue.prototype._lifecycleHooks.push('attached', function attached () {})中,我们可以看到在Vue实例的生命周期中添加一个‘attached’的钩子函数。
-
在Vue.directive('if', {})中,我们可以看到v-if指令的注册,主要包含了“终止”、“优先级”、“转译”、“更新”、“创建”和“解绑”功能。
接下来,我们来看一下v-show的实现方式:
Vue.directive('show', {
bind: function bindFn () {
var el = this.el,
transition = el.__v_trans,
enterClass, leaveClass
if (!transition) {
this._isDynamicLiteral = true
this._setupDynamicLiteral(this.arg)
}
if (transition && this.modifiers && this.modifiers.stop) {
transition.stop = this.modifiers.stop
}
if (transition && this.modifiers && this.modifiers.block) {
enterClass = el.getAttribute(transition.enterClass)
leaveClass = el.getAttribute(transition.leaveClass)
if (enterClass !== null && enterClass !== '') {
el._enterClass = enterClass
}
if (leaveClass !== null && leaveClass !== '') {
el._leaveClass = leaveClass
}
}
},
update: function updateFn (value) {
if (value) {
this.el.style.display = this.originalDisplay
} else {
this.originalDisplay = this.el.style.display
this.el.style.display = 'none'
}
},
unbind: function unbindFn () {
this.el.style.display = this.originalDisplay || ''
}
})
我们来解读一下上面的源代码:
-
在update函数中,我们可以看到当表达式的值为true时,v-show指令将元素的display属性设置为“display:block;”,使元素可见;当表达式的值为false时,v-show指令将元素的display属性设置为“display:none;”,使元素不可见。
-
在unbind函数中,我们可以看到v-show指令的解绑函数,主要用于恢复原来元素的display属性。
通过以上代码分析,我们可以非常清晰地看到v-if和v-show的实现方式和它们在源码中的区别。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:vue中v-if和v-show使用区别源码分析 - Python技术站