vite5+vue3+ import.meta.glob动态导入vue组件

import.meta.glob 是 Vite 提供的一个特殊功能,它允许你在模块范围内动态地导入多个模块。这在处理大量的文件,如组件、页面或其他模块时特别有用,特别是当你需要根据某些条件或模式来动态加载它们时。
1.创建需要动态导入的组件目录

假设你有一个src/pages/DynamicComponents目录,里面包含多个 Vue 组件,你想根据某些条件动态地导入这些组件。

首先,确保你的目录结构是这样的:

src/pages/index.vue文件

<template>
    <div class="DynamicComponentsOutbox">
        <h1>DynamicComponents</h1>
    </div>
    <div>
        <component v-for="(component, name) in dynamicComponents" :key="name" :is="component" />
    </div>
</template>
 
<script setup>
import { onMounted, reactive,markRaw } from 'vue'
const dynamicComponents = reactive({})
onMounted(async () => {
    const modules = import.meta.glob('./DynamicComponents/*.vue');
 
    for (const path in modules) {
        const module = await modules[path]();
        const componentName = path.replace(/^\.\/components\/(.*)\.vue$/, '$1');
        console.log(`componentName`,componentName );
      dynamicComponents[componentName] = markRaw(module.default)
     
    }
    console.log(`dynamicComponents`,dynamicComponents);
})
</script>
 
<style lang="scss" scoped></style>
     

src/pages/DynamicComponents/ComponentA.vue文件

    <template>
        <div class="">
            <h1>ComponentA</h1>
        </div>
    </template>
      
    <script setup>
     
     
    </script>
      
    <style lang="scss" scoped></style>

src/pages/DynamicComponents/ComponentB.vue文件

    <template>
        <div class="">
            <h1>ComponentB</h1>
        </div>
      </template>
      
      <script setup>
      
      
      </script>
      
      <style lang="scss" scoped>
      
      </style>

App.vue文件

    <template>
      <main>
        <HelloWorld msg="You did it!" />
        <component :is='DynamicComponents' ref="operateRowsDialogRef" @submitDialog="submitDialog"></component>
      </main>
    </template>
    <script setup>
    import HelloWorld from '@/components/HelloWorld.vue'
    import DynamicComponents from '@/pages/index.vue'
    </script>
    <style scoped></style>

也可以使用src/pages/index.vue文件,将文件名字更改为指定的文件名,然后使用文件名应用,使用同样
例如:
将改文件改为 operateDialog.vue

<template>
<operateDialog ref="operateDialogRef" @submitDialog="submitDialog"></operateRowsDialog>
</template>

<script setup lang="ts">
import operateDialog from '@/pages/operateDialog.vue'
</script>
    index.vue:6 
     [Vue warn]: Vue received a Component that 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: 'ed2b2297', __file: 'C:/Users/63002/Desktop/codefile/vue3-vite2/src/pages/DynamicComponents/ComponentA.vue', render: ƒ}
     
      at <Index> 
      at <App>

刚开始这样写

dynamicComponents[componentName] =module.default

这里报了一个警告:提示你去给组件使用markRaw or shallowRef包起来就好了,我直接使用了markRaw来包起组件 ,就解决这个警告了。

改为:


import { onMounted, reactive,markRaw } from 'vue'

dynamicComponents[componentName] = markRaw(module.default)

    <template>
        <div class="DynamicComponentsOutbox">
            <h1>DynamicComponents</h1>
        </div>
        <div>
            <component v-for="(component, name) in dynamicComponents" :key="name" :is="component" />
        </div>
    </template>
     
    <script setup>
    import { onMounted, reactive,markRaw } from 'vue'
    const dynamicComponents = reactive({})
    onMounted(async () => {
        const modules = import.meta.glob('./DynamicComponents/*.vue');
        for (const path in modules) {
            const module = await modules[path]();
            const componentName = path.replace(/^\.\/components\/(.*)\.vue$/, '$1');
            console.log(`componentName`,componentName );
          dynamicComponents[componentName] = markRaw(module.default)
         
        }
        console.log(`dynamicComponents`,dynamicComponents);
    })
    </script>
     
    <style lang="scss" scoped></style>

在上面的代码中,我们首先在onMounted钩子中使用 import.meta.glob 获取 components 目录下所有 .vue 文件的动态导入。然后,我们遍历这些模块,加载它们,并将它们存储在 dynamicComponents 对象中,其中键是组件的名称(从文件路径中提取),值是组件的默认导出。

最后,在模板中,我们使用 v-for 指令遍历 dynamicComponents 对象,并使用 Vue 的动态组件功能 () 来渲染每个组件。

注意:由于 import.meta.glob 是在构建时解析的,因此它不会为动态路径或运行时确定的路径工作。它主要用于静态路径模式。 

补充 调用指定组件的指定方法

在组件中暴露出对应的方法和组件名
例如暴露出open方法和名字 ,open为方法,name为名字

defineExpose({
  open,
  name: 'openDialog',
})

将src/pages/index.vue文件改写一下,使用ref方法获取实例

<template>
  <component
    ref="dynamicComponentsRef"
    v-for="(component, name) in dynamicComponents"
    :key="name"
    :is="component"
    @submitDialog="submitDialog"
  />
</template>

<script setup lang="ts">
import { provide, reactive, ref, watchEffect, computed, inject, nextTick, onMounted, markRaw } from 'vue'
const dynamicComponents = reactive({})
onMounted(async () => {
  const modules = import.meta.glob('./DynamicComponents/*.vue')
  for (const path in modules) {
    const module = await modules[path]()
    const componentName = path.replace(/^\.\/components\/(.*)\.vue$/, '$1')
    dynamicComponents[componentName] = markRaw(module.default)
  }
})
const dynamicComponentsRef = ref<any>(null)
const emit = defineEmits(['submitDialog'])
const submitDialog = (data?: any) => {
  emit('submitDialog', data)
}
// 传入参数 行数据(单选和多选都用列表传入),组件名称,type type 1单行点击 2多选点击
const open = (rowSelections: any, name: string, type?: number) => {
  let str = name
  const dynamicComponents = Array?.from(dynamicComponentsRef?.value) // 获取所有动态组件的实例数组
  dynamicComponents.forEach((component) => {
    if (component?.name == str) {
      component?.open(rowSelections, type) // 调用每个动态组件的 open() 方法
    }
  })
}
defineExpose({
  open,
})
</script>

<style scoped></style>

以上文件夹加载组件会出现组件卡顿的现象,可将文件夹加载组件改成异步实现,见官方文档使用说明

<script setup lang="ts">
import { shallowReactive,ref,onMounted, } from 'vue'
const modules = import.meta.glob('./DynamicComponents/*.vue', { eager: true, import: 'default' })
const dynamicComponents = shallowReactive<any>({})
onMounted(async () => {
  for (const path in modules) {
    const module = modules[path]
    const componentName = path.replace(/^\.\/components\/(.*)\.vue$/, '$1')
    dynamicComponents[componentName] = module
  }
})

补充 shallowReactive

  • 5
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值