动态组件
什么是动态组件?
动态组件是 Vue 中的一个重要特性,允许我们根据条件动态地切换不同的组件。在 Vue3 中,我们使用 <component> 元素配合 :is 属性来实现动态组件。
1. 基本使用
使用 <component :is="componentName"> 来动态渲染组件。
示例:基本动态组件
<template>
<div>
<div class="tabs">
<button
v-for="tab in tabs"
:key="tab.name"
@click="currentTab = tab.name"
:class="{ active: currentTab === tab.name }"
>
{{ tab.label }}
</button>
</div>
<div class="tab-content">
<!-- 动态组件 -->
<component :is="currentTab" />
</div>
</div>
</template>
<script>
// 导入组件
import HomeComponent from './HomeComponent.vue'
import AboutComponent from './AboutComponent.vue'
import ContactComponent from './ContactComponent.vue'
export default {
name: 'DynamicComponentDemo',
components: {
HomeComponent,
AboutComponent,
ContactComponent
},
data() {
return {
currentTab: 'HomeComponent',
tabs: [
{ name: 'HomeComponent', label: '首页' },
{ name: 'AboutComponent', label: '关于我们' },
{ name: 'ContactComponent', label: '联系我们' }
]
}
}
}
</script>
<style scoped>
.tabs {
display: flex;
gap: 10px;
margin-bottom: 20px;
}
.tabs button {
padding: 10px 20px;
border: 1px solid #ddd;
background-color: #f5f5f5;
cursor: pointer;
border-radius: 4px;
}
.tabs button.active {
background-color: #42b883;
color: white;
border-color: #42b883;
}
.tab-content {
padding: 20px;
border: 1px solid #ddd;
border-radius: 4px;
}
</style>
2. 组件缓存
使用 <KeepAlive> 组件可以缓存动态组件的状态,避免组件被频繁创建和销毁。
示例:缓存动态组件
<template>
<div>
<div class="tabs">
<button
v-for="tab in tabs"
:key="tab.name"
@click="currentTab = tab.name"
:class="{ active: currentTab === tab.name }"
>
{{ tab.label }}
</button>
</div>
<div class="tab-content">
<!-- 使用 KeepAlive 缓存组件 -->
<KeepAlive>
<component :is="currentTab" />
</KeepAlive>
</div>
</div>
</template>
<script>
// 导入组件
import { KeepAlive } from 'vue'
import HomeComponent from './HomeComponent.vue'
import AboutComponent from './AboutComponent.vue'
import ContactComponent from './ContactComponent.vue'
export default {
name: 'DynamicComponentDemo',
components: {
KeepAlive,
HomeComponent,
AboutComponent,
ContactComponent
},
data() {
return {
currentTab: 'HomeComponent',
tabs: [
{ name: 'HomeComponent', label: '首页' },
{ name: 'AboutComponent', label: '关于我们' },
{ name: 'ContactComponent', label: '联系我们' }
]
}
}
}
</script>
3. KeepAlive 的 include 和 exclude 属性
可以使用 include 和 exclude 属性来控制哪些组件需要被缓存。
示例:条件缓存
<template>
<div>
<!-- include:只缓存指定名称的组件 -->
<KeepAlive include="HomeComponent,AboutComponent">
<component :is="currentTab" />
</KeepAlive>
<!-- exclude:不缓存指定名称的组件 -->
<KeepAlive exclude="ContactComponent">
<component :is="currentTab" />
</KeepAlive>
<!-- 使用数组语法 -->
<KeepAlive :include="['HomeComponent', 'AboutComponent']">
<component :is="currentTab" />
</KeepAlive>
</div>
</template>
4. KeepAlive 的 max 属性
Vue 3.2+ 新增了 max 属性,用于限制缓存组件的最大数量。
示例:限制缓存数量
<template>
<div>
<!-- 最多缓存 2 个组件 -->
<KeepAlive :max="2">
<component :is="currentTab" />
</KeepAlive>
</div>
</template>
5. 动态组件的生命周期
当使用 <KeepAlive> 时,组件会触发额外的生命周期钩子:
onActivated:组件被激活时触发onDeactivated:组件被停用时触发
示例:使用激活和停用钩子
<script setup>
import { onMounted, onUnmounted, onActivated, onDeactivated } from 'vue'
onMounted(() => {
console.log('组件挂载')
})
onUnmounted(() => {
console.log('组件卸载')
})
onActivated(() => {
console.log('组件激活')
})
onDeactivated(() => {
console.log('组件停用')
})
</script>
6. 动态组件的异步加载
可以结合动态导入实现组件的异步加载,提高应用的初始加载性能。
示例:异步动态组件
<template>
<div>
<button @click="loadComponent">加载异步组件</button>
<div v-if="AsyncComponent">
<component :is="AsyncComponent" />
</div>
</div>
</template>
<script>
export default {
name: 'AsyncComponentDemo',
data() {
return {
AsyncComponent: null
}
},
methods: {
async loadComponent() {
// 动态导入组件
const module = await import('./AsyncComponent.vue')
this.AsyncComponent = module.default
}
}
}
</script>
7. 动态组件的高级用法
可以结合响应式数据和计算属性实现更复杂的动态组件逻辑。
示例:基于计算属性的动态组件
<template>
<div>
<select v-model="selectedType">
<option value="text">文本输入</option>
<option value="number">数字输入</option>
<option value="select">下拉选择</option>
</select>
<div class="form-field">
<component :is="currentComponent" v-model="fieldValue" />
</div>
<p>当前值: {{ fieldValue }}</p>
</div>
</template>
<script>
import TextInput from './TextInput.vue'
import NumberInput from './NumberInput.vue'
import SelectInput from './SelectInput.vue'
export default {
name: 'DynamicFormDemo',
components: {
TextInput,
NumberInput,
SelectInput
},
data() {
return {
selectedType: 'text',
fieldValue: ''
}
},
computed: {
currentComponent() {
// 根据类型返回不同的组件
const componentMap = {
text: 'TextInput',
number: 'NumberInput',
select: 'SelectInput'
}
return componentMap[this.selectedType]
}
}
}
</script>
使用场景
- 标签页(Tabs)切换
- 动态表单生成
- 路由视图(Vue Router)
- 模态框内容动态切换
- 根据用户权限显示不同组件
最佳实践
- 合理使用
<KeepAlive>缓存频繁切换的组件 - 使用
include和exclude精确控制缓存范围 - 对于大型组件,考虑使用异步加载
- 结合计算属性实现复杂的组件切换逻辑
- 注意
onActivated和onDeactivated钩子的使用