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

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

时间2025-09-19 14:44:18分类IT科技浏览5761
导读:内容有些啰嗦,内容记载了当时遇到了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
python或判断(any在python中判断对象为真)