vue3 使用defineAsyncComponent与component标签实现动态渲染组件

这篇具有很好参考价值的文章主要介绍了vue3 使用defineAsyncComponent与component标签实现动态渲染组件。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

内容有些啰嗦,内容记载了当时遇到了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、不能在组件的事件函数内挂载,
vue3 使用defineAsyncComponent与component标签实现动态渲染组件

2、不能在axios的then函数体内挂载
vue3 使用defineAsyncComponent与component标签实现动态渲染组件

3、不能在带有async声明的函数体内挂载
vue3 使用defineAsyncComponent与component标签实现动态渲染组件

4、不能在vue的生命周期内挂载
vue3 使用defineAsyncComponent与component标签实现动态渲染组件

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时就不会报错。文章来源地址https://www.toymoban.com/news/detail-446800.html

到了这里,关于vue3 使用defineAsyncComponent与component标签实现动态渲染组件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • vue3 -- 使用audio标签播放音频

    公司系统内的审批页面,前端要根据后台推送的信息,使用’提示音’提醒用户进行对应审批操作。 vue3 项目 简介 | Vue.js (vuejs.org) TypeScript TypeScript: JavaScript With Syntax For Types. (typescriptlang.org) vite Vite | 下一代的前端工具链 (vitejs.dev) 下载好使用音频文件 音效网,保存本地。 将

    2024年02月01日
    浏览(38)
  • h5音频标签模拟实现语音条(VUE3)

    思路:将原audio标签通过css隐藏,在通过css的div实现语音条样式,获取到audio的ref,操作audio的play、pause方法即可 效果图: template   div style=\\\"display: none\\\"     audio       controls       ref=\\\"audioRef\\\"       @loadedmetadata=\\\"handleLoadedMetadata\\\"       @ended=\\\"audioEnded\\\"           !-- source :src=\\\"

    2024年03月20日
    浏览(36)
  • vue3中使用ant-design-vue的layout组件实现动态导航栏功能(1~2级)

    目录 0 前言 1 准备工作 1.1 安装ant-design-vue 1.2 安装图标组件包 2 选择组件 3 路由文件 4 Vue导航页面 5 最终效果         最近在自己搞一个前后端小项目,前端想使用ant-design-vue的layout组件实现动态导航栏和面包屑,但是网上的资料较少,所以我就自己整合实现了一下,在此

    2024年02月15日
    浏览(36)
  • Vue3-在HTML标签、组件标签上使用v-model

    本篇为Vue3学习中遇到的v-model相关的记录,如有问题欢迎指正 v-model通常在input、select等标签上来实现数据双向绑定 原理 :v-model通过给标签value赋值来实现  数据—页面 的绑定。然后通过绑定input事件实现 页面—数据 的绑定。 原理 :在组件上时,v-model通过 :modelValue 来进行

    2024年01月24日
    浏览(56)
  • Vue3实现可视化拖拽标签小程序

    实现功能:可视化标签拖拽,双击标签可修改标签内容 一个大DIV包含里面存放两个DIV一个input header为头部标签名称 内容区域绑定双击鼠标事件,触发开始修改事件(startEditing),使用v-if进行标签的显示和隐藏操作 input标签,事件绑定为修改内容,绑定获取焦点事件(@blue=“

    2024年02月09日
    浏览(44)
  • [VUE学习]权限管理系统前端vue实现9-动态路由,动态标签页,动态面包屑

                    在总体布局页面添加router router-view 是 Vue Router 提供的组件,用于动态展示匹配到的路由组件内容。 通过在合适的位置放置 router-view ,你可以根据路由路径动态地渲染对应的组件内容。                     因为我们是多级页面 之后动态路由也是多级的 如

    2024年02月13日
    浏览(42)
  • uni-app:vue3 + uni-app 在微信小程序中无法使用app.component全局注册组件

    按上文中的代码执行后,会发现在微信小程序开发中全局注册的组件是无法显示的,这是uniapp的一个未解决bug, 在uniapp中出了可以通过vue实例的component方法注册全局组件外,uniapp支持另一种全局注册的方式,就是通过 easycom 扫描注册,步骤如下 easycom 的扫描流程是:通过代码

    2024年02月16日
    浏览(79)
  • vue3利用 a 标签,文件流,JSZip 压缩包,实现文件下载

    在实现文件的下载,采用 a 标签,会出现图片,没有进行下载,而是,在当前页面打开了图片。 导致原因: ·a标签,有 download 属性,可以实现下载 同源文件( ip 和 端口 相同),当图片不同源 时,点击下载,会在当前窗口直接打开图片,而不是进入下载状态。 1.1 没有图片

    2023年04月08日
    浏览(34)
  • vue给components动态添加组件

    在Vue中,可以使用 v-bind 指令来动态地将组件添加到其他组件上。 首先,需要定义一个包含所有可能的子组件的数组或对象。然后,通过计算属性(computed property)根据条件选择要显示的组件。最后,使用 component 元素并结合 is 特性来动态地切换不同的组件。 这样就可以根据

    2024年01月24日
    浏览(39)
  • vue3 +element动态表单实现

    可以直接复制,接口看后端 父页面 子页面

    2024年02月15日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包