在页面应用程序中,经常会遇到多标签页面,在Vue.js中,可以通过动态组件来实现。组件的动态切换是通过在<component>
元素上使用is
属性实现的。
实现效果如下:
上图中的3个标签是3个按钮,下面的内容部分由组件来实现,3个按钮对应3个组件,按钮响应click事件,单机不同按钮时切换至不同的组件,组件切换通过<component>
元素和其上的is
属性实现。
3个组件的实现代码如下:
app.component('tab-introduce', {
data(){
return {
content: 'Java无难事'
}
},
template: '<div><input v-model="content"></div>'
})
app.component('tab-comment', {
template: '<div>这是一本好书</div>'
})
app.component('tab-qa', {
template: '<div>有人看过吗?怎么样?</div>'
})
第一个组件的模板使用了一个<input>
元素,便于我们修改内容,这主要是为了引出后面的知识点。
在根实例中定义了两个数据属性和一个计算属性,主要是为了便于使用v-for指令循环渲染button按钮,以及动态切换组件。代码如下所示:
const app = Vue.createApp({
data() {
return {
currentTab: 'introduce',
tabs: [
{title: 'introduce', displayName: '图书介绍'},
{title: 'comment', displayName: '图书评价'},
{title: 'qa', displayName: '图书问答'}
]
}
},
computed: {
currentTabComponent: function () {
return 'tab-' + this.currentTab
}
}
})
数据属性currentTab代表当前的标签页,tabs是一个数组对象,通过v-for指令渲染代表标签的3个按钮,计算属性currentTabComponent代表当前选中的组件。 接下来就是在与实例关联的DOM模板中渲染按钮,以及动态切换组件的代码。代码如下所示:
<div id="app">
<button
v-for="tab in tabs"
:key="tab.title"
:class="['tab-button', { active: currentTab === tab.title }]"
@click="currentTab = tab.title">
{{ tab.displayName }}
</button>
<keep-alive>
<component
:is="currentTabComponent"
class="tab">
</component>
</keep-alive>
</div>
当单击某个标签按钮时,更改数据属性currentTab的值,这将导致计算属性currentTabComponent的值更新,<component>
元素的is属性使用v-bind指令绑定到一个已注册的名字上,随着计算属性currentTabComponent值的改变,组件也就自动切换了。
剩下的就是CSS样式的设置了。完整的代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>动态组件</title>
<style>
div {
width: 400px;
}
.tab-button {
padding: 6px 10px;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
border: solid 1px #ccc;
cursor: pointer;
background: #f0f0f0;
margin-bottom: -1px;
margin-right: -1px;
}
.tab-button:hover {
background: #e0e0e0;
}
.tab-button .active {
background: #cdcdcd;
}
.tab {
border: solid 1px #ccc;
padding: 10px;
}
</style>
</head>
<body>
<div id="app">
<button
v-for="tab in tabs"
:key="tab.title"
:class="['tab-button', { active: currentTab === tab.title }]"
@click="currentTab = tab.title">
{{ tab.displayName }}
</button>
<keep-alive>
<component
:is="currentTabComponent"
class="tab">
</component>
</keep-alive>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
const app = Vue.createApp({
data() {
return {
currentTab: 'introduce',
tabs: [
{title: 'introduce', displayName: '图书介绍'},
{title: 'comment', displayName: '图书评价'},
{title: 'qa', displayName: '图书问答'}
]
}
},
computed: {
currentTabComponent: function () {
return 'tab-' + this.currentTab
}
}
})
app.component('tab-introduce', {
data(){
return {
content: 'Java无难事'
}
},
template: '<div><input v-model="content"></div>'
})
app.component('tab-comment', {
template: '<div>这是一本好书</div>'
})
app.component('tab-qa', {
template: '<div>有人看过吗?怎么样?</div>'
})
app.mount('#app');
</script>
</body>
</html>
上述代码中的第一个组件模板使用了一个<input>
元素,因此可以修改该组件的内容,修改后,切换到其他标签页,然后再切换回来,你会发现之前修改的内容并没有保存下来,这是因为每次切换新标签的时候,Vue都创建一个新的currentTabComponent实例。在本例中,希望组件在切换的时候,可以保持组件的状态,以避免重复渲染导致的性能问题,也为了让用户的体验更好。要解决这个问题,可以用一个<keep-alive>
元素将动态组件包裹起来。代码如下所示:
<keep-alive>
<component
:is="currentTabComponent"
class="tab">
</component>
</keep-alive>
渲染结果:
修改
切换标签之后
可以看到,组件的状态被保存了下来。