Vue动态组件

项目中,经常会遇到不同组件之间进行动态切换,如 Tab 菜单栏。

通常的实现方式,我们会选择二级路由,但是这就需要管理路由,所以使用起来并不是特别方便。

动态组件的方式,给我们带来了更简洁的动态切换组件的方式。

在 Vue 中,通过给 <component> 元素添加 is 属性来实现动态组件切换业务。

is 表示要动态加载的组件名称或组件的选项对象。

1
2
<!-- 组件会在 `currentTabComponent` 改变时改变 -->
<component v-bind:is="currentTabComponent"></component>

运用

如上图所示需求,具体实现如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<div id="app">
<div class="tabbar">
<button class="tab-item" :class="{'tab-item--active' : tabItem === 'tab-item-one'}" @click="tabItem = 'tab-item-one'">tab-item-one</button>
<button class="tab-item" :class="{'tab-item--active' : tabItem === 'tab-item-two'}" @click="tabItem = 'tab-item-two'">tab-item-two</button>
<component class="tab-content" :is="tabItem"></component>
</div>
</div>

Vue.component('tab-item-one', {
template: ` <div>I am tab-item-one</div> `
})
Vue.component('tab-item-two', {
template: `<div>I am tab-item-two</div>`
})
// <input name="check" type="checkbox">
new Vue({
el: '#app',
data: function () {
return {
tabItem: 'tab-item-one'
}
}
})

当点击 button 按钮时,tabItem 的值会被设置为一个组件的名字(tab-item-one or tab-item-two),并赋值给 is 属性,那么 <component> 就会动态的替换为对应名称的组件。这就是动态组件的实现。

但是上面的代码也会存在一个问题,就是动态组件切换时,会把之前的组件销毁,等到再次切换到某一组件时,其实是重新创建了该组件。这样就无法使得组件在切换时,无法保留之前的状态了!

例如,我们把组件 tab-item-one 调整一下:

1
2
3
4
5
6
7
8
Vue.component('tab-item-one', {
template: `
<div>
I am tab-item-one
<input name="check" type="checkbox">
</div>
`
})

页面效果如图所示

2

当切换到组件 tab-item-one ,将 checkbox 勾选框选中为勾选状态,然后选中 tab-item-two 切换到 tab-item-two 组件,再次选中 tab-item-one,我们会发现组件内的checkbox 处于未勾选的状态。即我们tab-item-two 的状态丢失了。

正如我们上面说的,动态组件在切换时,是基于销毁和创建新组件的过程。那么对于需要保留已显示过的组件,如何保留其状态呢?

答案就是,使用 <keep-alive> ,将组件设置为状态持续。

因此我们队代码进行如下修正:

1
2
3
4
5
6
7
8
9
<div id="app">
<div class="tabbar">
<button class="tab-item" :class="{'tab-item--active' : tabItem === 'tab-item-one'}" @click="tabItem = 'tab-item-one'">tab-item-one</button>
<button class="tab-item" :class="{'tab-item--active' : tabItem === 'tab-item-two'}" @click="tabItem = 'tab-item-two'">tab-item-two</button>
<keep-alive>
<component class="tab-content" :is="tabItem"></component>
</keep-alive>
</div>
</div>

这样一来,切换过程中就会将所有的组件状态进行保存了。对于动态组件的使用我们已经了解了,至于如何更优雅的使用,就需要结合实际的场景了。