首页IT科技vue组件如何渲染到页面(vue3 使用defineAsyncComponent与component标签实现动态渲染组件)

vue组件如何渲染到页面(vue3 使用defineAsyncComponent与component标签实现动态渲染组件)

时间2025-08-04 14:04:22分类IT科技浏览4977
导读:内容有些啰嗦,内容记载了当时遇到了bug以及解决问题的思路。...

内容有些啰嗦               ,内容记载了当时遇到了bug以及解决问题的思路               。

业务场景简述: 前端做配置化组件                      ,通过url内的唯一标识      ,请求后端sql 哪取页面配置信息           ,前端通过配置信息动态渲染查询表单                       ,导出              、表格         ,toolbar以及动态弹窗;该动态渲染组件的功能       ,就是渲染的toolbar内的按钮                        ,类型为自定义弹窗             ,弹窗路径为后端配置数据   ,前端通过点击该按钮                       ,打开指定路径下的弹窗组件                      。

之前用的vue2的动态挂载组件                 ,也没见vue3那么麻烦,官网上的例子以及网上的所以例子都是前端知道要导哪些组件                   ,然后程序进入就直接导进来了                     ,只是写了逻辑动态切换      。我这个不一样   ,需要挂载的组件是未知的           。所以实现起来有点吃力                       。

一                     、基础的动态引入组件: 简单的动态引入的意思是               ,前端知道要引入哪些组件                      ,将多个组件引入到父组件中      ,但不渲染它           ,满足一定条件后                       ,才去在某个位置渲染指定的组件         。

<template> <custom-modal ref="custom"></custom-modal> </template> <script> import { reactive, ref, shallowReactive, onActivated, defineAsyncComponent, } from vue; const customModal = defineAsyncComponent(() => import(./modal/CustomModal.vue)); const custom = ref(); </script>

以上的例子就是通过vue的defineAsyncComponent实现挂载组件         ,并赋值给customModal        ,模板中可以直接使用<custom-modal>作为标签使用,也可以将它赋值给component中的is属性                        ,is属性执向一个变量             ,可通过业务逻辑动态   ,更改该变量的值                       ,就可以实现多个组件进行来回的渲染了

<template> <component :is="componentKey" ref="custom"></component> </template> import { reactive, ref, shallowReactive, onActivated, defineAsyncComponent, } from vue; const componentKey = ref(null); const components: any = shallowReactive({}); const customModal = defineAsyncComponent(() => import(./modal/CustomModal.vue)); componentKey = customModal

二        、复杂的引入:不确定到底引入什么组件                 ,组件的路径由后端返回

将以上代码 添加到项目代码中,并不能实现                   ,虽然引入不报错                     ,但是ref一直为undefined   ,无法调用动态组件内的open函数       。

不断尝试了很多次               ,得出以下结论 1.起初是在按钮的click函数内去挂载自定义组件并调用ref函数的                      ,ref为undefined                        。 尝试多次不能实现功能(这里是挂载与调用最合适的位置)      , 2.接着又在初始化配置数据时(查询后端sql)           ,axios的then函数内挂载组件                       ,然后点击按钮的地方调用ref内的函数         ,ref依旧为null             。 3. 接着在最外层       ,调用初始化时挂载                        ,也就是生命周期函数体内             ,测试还是一样的结果   。 4. 接着发现带有async函数体内挂载组件   ,也无法完成                       。 5.单独写个函数                       ,不加async                 ,函数内挂载组件,然后再生命周期外调用该函数                   ,按钮内调用ref内的方法                     ,成功弹窗                 。这并不是我想要的   ,因为路径不是固定的               ,它要等到后端sql放回结果                      ,才能执行。

总结:上面的多次测试      ,得出以下结论           ,都不能让动态组件ref对象有值

1           、不能在组件的事件函数内挂载                       ,

2                    、不能在axios的then函数体内挂载

3            、不能在带有async声明的函数体内挂载

4        、不能在vue的生命周期内挂载

5                    、只能在最外层挂载实现         ,这时ref才是个对象                   。

好在天无绝人之路;脑海里有个思路:

页面初始化时将项目里所有的全局挂载view组件扔到一个object内       ,使用component组件                        ,is:对应object内指定的组件对象             ,然后通过后端的数据   ,这时后端就不用给组件路径了                       ,给个组件名                 ,我从object中找到挂载的组件然后将对象给is                     。

const modules = import.meta.glob(@/views/*/**.vue); // 获取所有项目路径

mudules为views内所有的vue的相对路径,然后循环它                   ,在循环体内实现挂载                     ,将它存入一个对象内   ,key为相对路径的项目名称(可以截取以下)   。

有了上面的思路               ,通过反复测试和实现                      ,最终功能实现了               。

<template> <component :is="componentKey" ref="custom"></component> </template> <script> import { reactive, ref, shallowReactive, onActivated, defineAsyncComponent, } from vue; //声明componentkey,用于告诉component当前挂载什么组件      ,components为一个对象           ,存放多个不确定的自定义组件                      。 const componentKey = ref(null); const components: any = shallowReactive({}); // 组件挂载 const initTableConfig = (gridId, type) => { queryTableConfig({ gridId }).then(({ data }) => { if (type === main) { Object.assign(mainConfig, data); tabsKey.value = -1; } else { tabsDetail.value.push(data); tabsKey.value = tabsDetail.value.length - 1; } // 涉及到自定义组件的部分                       ,这里需要提前挂载         ,在用到时不至于ref为null XEUtils.objectEach(data.action, (action, key) => { if ( action.modalCfg && action.modalCfg.type === CustomModal && action.modalCfg.src ) { components[action.actionId] = defineAsyncComponent( () => import(`../../../${action.modalCfg.src}`) ); //注意:这里的路径后端只能返回相对路径       ,不能使用@/xxx/xxx.vue ,不能使用src/xxx/xxx.vue                        ,只能./xxx.vue或者../../xxx/xxx.vue      。由于并不确定组件在什么位置             ,避免容易出错的原则   ,我在前端通过../../../的形式将路径回退到src下                       ,后端只需要从src下配置路径即可                 ,不用考虑那么多了           。如后端src的值为src/xxx/xxx/xxx.vue 则在前端合成的路径就为../../../src/xx/xxx/xxx.vue componentKey.value = components[action.actionId]; // 为什么componentKey.vue在这里赋值,在后面点击窗口后又赋值                   ,这里能不能省略                       。 // 答:这里省略的话                     ,到点击按钮触发时会报错   ,第一次点击会报错               ,第二次点击不会报错                      ,窗口正常弹出         。可能是因为      ,组件挂载时并没有引入组件           ,只在使用时才引入                       ,如果上面不提前将挂载好的组件引入进来         ,后面触发事件触发时引入在调用ref       ,执行太快                        ,costom就会报错             ,所以才会点两次才弹窗       。 } }); }); }; </script>

按钮点击触发事件   ,确定弹窗要弹出什么组件

} else if (action.modalCfg.type === CustomModal) { // 这里的actionid和组件是对应的                       ,所以在按钮触发后                 ,通过按钮携带的actionid能取到对应的组件                        。 componentKey.value = components[action.actionId]; custom.value.init(row); }

经过以上的方式:在任何地方挂载都不会报错,完美解决             。

注意:挂载与使用ref不能在同一个方法体内                   ,如果可以的话                     ,页面加载时   ,执行挂载               ,需要调用ref时就不会报错   。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
易优cms破解商城链接(易优CMS自动采集伪原创发布) html边框属性有哪些(HTML中关于边框(border)的使用)