vuejs3.0 从入门到精通——动态组件
动态组件
一、App.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | <template> <ul> <!-- 使用ul标签替代了错误的url标签,用于展示列表 --> <li v- for = '(item, index) in tabList' :key= 'index' @click= "() => { currentComponent.com = tabList[index].com }" > <!-- 使用v- for 指令遍历tabList数组,生成列表项,其中item是当前遍历的元素,index是索引 --> {{ item.name }} <!-- 使用双大括号插值表达式展示item的name属性 --> </li> </ul> <component :is= "currentComponent.com" ></component> <!-- :is 是一个特殊的属性,用于动态地绑定一个组件到其标签名。根据currentComponent.com的值来决定具体渲染哪个组件 --> </template> <script setup lang= "ts" > import { reactive } from 'vue' ; // 引入vue的reactive API,用于创建响应式对象 import A from './components/A.vue' ; // 引入A组件 import B from './components/B.vue' ; // 引入B组件 import C from './components/C.vue' ; // 引入C组件 import { DefineComponent } from 'vue' ; // 引入DefineComponent类型,用于更精确地定义组件类型 interface TabItem { // 定义TabItem接口,用于约定tabList中对象的结构 name: string; // name属性是字符串类型 com: DefineComponent<any, any, any>; // com属性是一个组件类型,这里使用any是为了简化,实际使用时需要具体定义组件的props、emits等类型 } let tabList = reactive<TabItem[]>([ // 创建响应式对象tabList,它的类型是TabItem数组 { name: 'A准备好面试题' , com: A }, // 数组的第一个元素,name是字符串,com是A组件 { name: 'B准备简历' , com: B }, // 数组的第二个元素,name是字符串,com是B组件 { name: 'C准备面试' , com: C } // 数组的第三个元素,name是字符串,com是C组件 ]); let currentComponent = reactive<any>({ com: tabList[0].com }); // 创建响应式对象currentComponent,它的类型是any,初始时com属性指向tabList的第一个元素的com属性,即A组件 </script> |
二、components
A.vue:
1 2 3 4 5 6 7 | <!--子组件: A 组件--> <template> <div> <h1>A组件</h1> </div> </template> |
B.vue:
1 2 3 4 5 6 7 | <!--子组件: B 组件--> <template> <div> <h1>B组件</h1> </div> </template> |
C.vue:
1 2 3 4 5 6 7 | <!--子组件: C 组件--> <template> <div> <h1>C组件</h1> </div> </template> |
三、运行结果
四、console有报错
这里我将告警信息文字化,便于同道们搜索。
App.vue:5 [Vue warn]: Vue received a Component which was made a reactive object. This can lead to unnecessary performance overhead, and should be avoided by marking the component with `markRaw` or using `shallowRef` instead of `ref`.
Component that was made reactive: {__hmrId: '65097ce7', __file: 'D:/worker-vue3/vite-project/src/components/A.vue', render: ƒ}
告警解释如下:
1 2 3 4 5 6 7 | 这个报错信息与 Vue 3 的响应式系统有关。在 Vue 3 中,使用了 reactive 和 ref 等 API 来创建响应式对象或值,以便在它们发生变化时能够自动更新相关的组件。 然而,在某些情况下,我们可能不希望某些对象或组件被转化为响应式的。在这种情况下,可以使用 markRaw 或者在创建引用时使用 shallowRef,以减少不必要的性能开销。 报错信息告诉我们,一个组件被转化成了响应式对象,这可能会导致性能上的不必要开销。它建议我们使用 markRaw 或者 shallowRef 来避免这种情况。 具体来说: markRaw:此函数可以标记一个对象,使其不会被转化为响应式的。这意味着该对象的任何变化都不会触发组件的更新。 shallowRef:这是一种创建引用的方式,与 ref 不同,它创建的引用只会在其直接引用的值发生变化时触发更新,而不会深入到引用的内部去检测其属性的变化。 在你的情况下,如果 A.vue 组件不应该被转化为响应式的,你可以尝试使用 markRaw 来标记它。如果 A.vue 组件需要被转化为响应式的,但其内部某些属性不需要被响应式,你可以尝试使用 shallowRef 来创建这些属性的引用。 |
五、修正
App.vue:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | <template> <ul> <!-- 遍历tabList数组生成列表项,点击列表项时会修改currentComponent.com的值为点击的列表项的com属性值 --> <li v- for = '(item, index) in tabList' :key= 'index' @click= "() => { currentComponent.com = item.com }" > {{ item.name }} </li> </ul> <!-- keep-alive 是Vue提供的一个内置组件, 它可以使被包含的组件缓存不销毁, 当组件切换时不会对当前组件进行卸载, 以优化性能。 当组件再次渲染时,会保留之前的状态。 --> <keep-alive> <component :is= "currentComponent.com" ></component> <!-- 将component组件作为KeepAlive的唯一子组件 --> <!-- 根据currentComponent.com的值动态渲染对应的组件 --> </keep-alive> </template> <script setup lang= "ts" > import { markRaw, reactive } from 'vue' ; import A from './components/A.vue' ; import B from './components/B.vue' ; import C from './components/C.vue' ; import { DefineComponent } from 'vue' ; // 定义TabItem接口,约定tabList中的对象结构 interface TabItem { name: string; com: DefineComponent<any, any, any>; } let tabList = reactive<TabItem[]>([ /* markRaw(A)的作用是在创建响应式对象时,将组件A标记为非响应式的,这样A组件就不会被Vue的响应式系统追踪变化,从而提高性能。 也就是说,即使currentComponent.com的值变为A组件,A组件也不会因为响应式系统的变化而重新渲染。 */ { name: 'A准备好面试题' , com: markRaw(A) }, { name: 'B准备简历' , com: markRaw(B) }, { name: 'C准备面试' , com: markRaw(C) } ]); // 创建响应式对象currentComponent,初始时com属性指向tabList的第一个元素的com属性 let currentComponent = reactive<any>({ com: tabList[0].com }); </script> |
分类:
Vue3专题精讲
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具