Vue3中的动态组件详解
作者:秀秀_heo
本文介绍了Vue3中的动态组件,通过`<component :is="动态组件名或组件对象"></component>`来实现根据条件动态渲染不同的组件,此外,还提到了使用`markRaw`和`shallowRef`来优化性能,避免不必要的响应式劫持
Vue3动态组件
动态组件的基本使用
动态组件(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 的值,解决性能浪费的问题
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。