动态组件的基本使用
动态组件(Dynamic Components)是一种在 Vue 中根据条件或用户输入来动态渲染不同组件的技术。
在 Vue 中使用动态组件,可以使用 <component>
元素,并通过 is 特性绑定一个组件的名称或组件对象。通过在父组件中改变 is 特性的值,可以动态切换渲染的组件。
第一种写法
A.vue
<template>
<div>
A component
</div>
</template>
<script setup lang="ts">
</script>
<style scoped></style>
B.vue, C.vue 同理
APP.vue
<template>
<div style="display: flex;">
<!-- class可以写两个,一个静态,一个动态 -->
<div @click="switchCom(item, index)" :class="[active == index ? 'active' : '']" class="tabs"
v-for="(item, index) in data">
<div>{{ item.name }}</div>
</div>
</div>
<component :is="comId"></component>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue';
import AVue from './components/A.vue'
import BVue from './components/B.vue'
import CVue from './components/C.vue'
// 这里不需要将对象中所有数据变为响应式,可以使用ref
const comId = ref(AVue)
const active = ref(0)
const switchCom = (item, index) => {
comId.value = item.com
active.value = index
}
const data = reactive([
{
name: 'A',
com: AVue
},
{
name: 'B',
com: BVue
},
{
name: 'C',
com: CVue
}
])
</script>
<style lang="scss" scoped>
.active {
background: blueviolet;
}
.tabs {
border: 1px solid #ccc;
padding: 5px 10px;
margin: 5px;
cursor: pointer;
}
</style>
第二种写法
APP.vue
<template>
<div style="display: flex;">
<!-- class可以写两个,一个静态,一个动态 -->
<div @click="switchCom(item, index)" :class="[active == index ? 'active' : '']" class="tabs"
v-for="(item, index) in data">
<div>{{ item.name }}</div>
</div>
</div>
<component :is="comId"></component>
</template>
<script setup lang="ts">
// markRaw:作用:标记一个对象,使其永远不会再成为响应式对象。
import { ref, reactive, markRaw, shallowRef } from 'vue';
// 这里不需要将对象中所有数据变为响应式,可以使用ref
const comId = shallowRef('AVue')
const active = ref(0)
const switchCom = (item, index) => {
comId.value = item.com
console.log(comId.value);
active.value = index
}
const data = reactive([
{
name: 'A',
com:'AVue'
},
{
name: 'B',
com:'BVue'
},
{
name: 'C',
com:'CVue'
}
])
</script>
<script lang="ts">
import AVue from './components/A.vue'
import BVue from './components/B.vue'
import CVue from './components/C.vue'
export default {
components: {
AVue,
BVue,
CVue
}
}
</script>
<style lang="scss" scoped>
.active {
background: blueviolet;
}
.tabs {
border: 1px solid #ccc;
padding: 5px 10px;
margin: 5px;
cursor: pointer;
}
</style>
性能优化
上述第一种写法代码会出现警告
输出 comId 的值,出现 comId 的属性被劫持,出现性能浪费
解决方法
使用markRaw
和shallowRef
这两个API
App.vue
<template>
<div style="display: flex;">
<!-- class可以写两个,一个静态,一个动态 -->
<div @click="switchCom(item, index)" :class="[active == index ? 'active' : '']" class="tabs"
v-for="(item, index) in data">
<div>{{ item.name }}</div>
</div>
</div>
<component :is="comId"></component>
</template>
<script setup lang="ts">
// markRaw:作用:标记一个对象,使其永远不会再成为响应式对象。
import { ref, reactive, markRaw, shallowRef } from 'vue';
import AVue from './components/A.vue'
import BVue from './components/B.vue'
import CVue from './components/C.vue'
// 这里不需要将对象中所有数据变为响应式,可以使用ref
const comId = shallowRef(AVue)
const active = ref(0)
const switchCom = (item, index) => {
comId.value = item.com
console.log(comId.value);
active.value = index
}
const data = reactive([
{
name: 'A',
com: markRaw(AVue)
},
{
name: 'B',
com: markRaw(BVue)
},
{
name: 'C',
com: markRaw(CVue)
}
])
</script>
<style lang="scss" scoped>
.active {
background: blueviolet;
}
.tabs {
border: 1px solid #ccc;
padding: 5px 10px;
margin: 5px;
cursor: pointer;
}
</style>
再次输出 comId 的值,解决性能浪费的问题