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

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

时间2025-06-14 07:50:30分类IT科技浏览4267
导读:内容有些啰嗦,内容记载了当时遇到了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
如何让网站被百度收录(选好关键词,为网站加分) vuexss(vue学习笔记)