当我们想做出一个toggle的效果,比如点击一下显示文字1,再点击显示文字2,再点击显示文字1....这样交替进行的时候,大家是怎么做的呢?
v-if的使用
用v-if控制切换是一种方法,想用v-show也可以,如下展示v-if方法
代码语言:javascript复制<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>动态组件与v-once指令
</title>
<script src="https://unpkg.com/vue"></script>
</head>
<body>
<div id="app">
<child-one v-if="comName === 'child-one'"></child-one>
<child-two v-if="comName === 'child-two'"></child-two>
<button @click="handleClick">按钮</button>
</div>
<script>
Vue.component('child-one', {
template: '<div>child-one</div>'
})
Vue.component('child-two', {
template: '<div>child-two</div>'
})
var vm = new Vue({
el: '#app',
data: {
comName: 'child-one'
},
methods: {
handleClick(){
this.comName = this.comName === 'child-one' ? 'child-two' : 'child-one';
}
}
})
</script>
</body>
</html>
运行结果
当if条件不成立,组件就会被销毁,条件成立,组件就会被创建,这样就是来回的创建和销毁的过程,有点耗费性能。
component动态组件的使用
接着我们展示动态组件compenent的用法
代码语言:javascript复制<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>动态组件与v-once指令
</title>
<script src="https://unpkg.com/vue"></script>
</head>
<body>
<div id="app">
<compnent :is="comName"></compnent>
<!-- <child-one v-if="comName === 'child-one'"></child-one>
<child-two v-if="comName === 'child-two'"></child-two> -->
<button @click="handleClick">按钮</button>
</div>
<script>
Vue.component('child-one', {
template: '<div>child-one</div>'
})
Vue.component('child-two', {
template: '<div>child-two</div>'
})
var vm = new Vue({
el: '#app',
data: {
comName: 'child-one'
},
methods: {
handleClick(){
this.comName = this.comName === 'child-one' ? 'child-two' : 'child-one';
}
}
})
</script>
</body>
</html>
运行效果图和上面用v-if一模一样,会根据:is="xxx"的is里面数据的变化自动加载不同的组件,效果和v-if相同,显示另一个组件之前会销毁掉当前组件
v-once指令的使用
这样来回切换不断销毁和创建也是挺耗费性能的,有没有一种办法能把组件缓存起来呢?避免重复销毁创建过程,答案是有的
代码语言:javascript复制<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>动态组件与v-once指令
</title>
<script src="https://unpkg.com/vue"></script>
</head>
<body>
<div id="app">
<!-- <compnent :is="comName" v-once></compnent> -->
<child-one v-once v-if="comName === 'child-one'"></child-one>
<child-two v-once v-if="comName === 'child-two'"></child-two>
<button @click="handleClick">按钮</button>
</div>
<script>
Vue.component('child-one', {
template: '<div>child-one</div>'
})
Vue.component('child-two', {
template: '<div>child-two</div>'
})
var vm = new Vue({
el: '#app',
data: {
comName: 'child-one'
},
methods: {
handleClick(){
this.comName = this.comName === 'child-one' ? 'child-two' : 'child-one';
}
}
})
</script>
</body>
</html>
运行结果图示和第一个例子一样
记住这里不能在component上面加上v-once,否则不会有切换效果。
因为v-once只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。顾名思义动态组件component的使用,"动态component"被视为"静态",自然就是切换不了的了。就像是优化器在AST打上了标记认为是静态子树(静态节点),比如一个纯文本节点就是静态子树,如果一个节点被标记为静态,那么除了首次渲染生成节点之外,在重新渲染的时候并不会生成新的节点,而是克隆已存在的静态节点。
渲染普通的 HTML 元素在 Vue 中是非常快速的,但有的时候你可能有一个组件,这个组件包含了大量静态内容。在这种情况下,你可以在根元素上添加 v-once
属性以确保这些内容只计算一次然后缓存起来。这就和v-show达到了同样的效果。
官方给出的注意点:不要过度使用这个模式。当你需要渲染大量静态内容时,极少数的情况下它会给你带来便利,除非你非常留意渲染变慢了,不然它完全是没有必要的——再加上它在后期会带来很多困惑。例如,设想另一个开发者并不熟悉 v-once
或漏看了它在模板中,他们可能会花很多个小时去找出模板为什么无法正确更新。
v-if v-once能否取代v-show?
v-if v-once其实在一定的程度上效果和v-show效果是相同的,比如上面的例子,用v-if v-once也是来回切换,v-once把组件缓存起来了,避免了来回创建销毁耗费的性能,而v-show也可以是一样的效果。
我所观察到的区别:
1、DOM结构上的区别
v-show是display的none和block的切换,组件被渲染并一直保留在 DOM 中,而v-if是组件销毁创建的切换,销毁的组件显示为<!---->,加上v-once可以在内存上优化,达到和v-show一样的效果。
2、限制上的区别
v-show不支持 <template>
元素,而v-if支持,这里可以用v-if v-once达到v-show的性能。
举个例子
代码语言:javascript复制<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>动态组件与v-once指令
</title>
<script src="https://unpkg.com/vue"></script>
</head>
<body>
<div id="app">
<template v-once v-if="comName === 'child-one'">
<div>这是v-if v-once的child-one</div>
</template>
<template v-show="comName === 'child-one'">
<div>
这是v-show的child-one,在template上始终显示,没有判断效果
</div>
</template>
<button @click="handleClick">按钮</button>
</div>
<script>
Vue.component('child-one', {
template: '<div>child-one</div>'
})
Vue.component('child-two', {
template: '<div>child-two</div>'
})
var vm = new Vue({
el: '#app',
data: {
comName: 'child-one'
},
methods: {
handleClick(){
this.comName = this.comName === 'child-one' ? 'child-two' : 'child-one';
}
}
})
</script>
</body>
</html>
运行效果:
我们可以看到不管条件为真还是为假,v-show已经完全失去了判断作用,足以说明在<template>上面是无效的