Skip to content

自动导入+动态组件

Nuxt项目(Vite)

代码图

ts
import { defineAsyncComponent } from 'vue'
const componentMap = {}
for (const [path, defineComponent] of Object.entries(
  import.meta.glob('@/components/home/module*.vue')
)) {
  const id = parseInt(path.split('module')[1])
  componentMap[id] = defineAsyncComponent(defineComponent)
}
import { defineAsyncComponent } from 'vue'
const componentMap = {}
for (const [path, defineComponent] of Object.entries(
  import.meta.glob('@/components/home/module*.vue')
)) {
  const id = parseInt(path.split('module')[1])
  componentMap[id] = defineAsyncComponent(defineComponent)
}
vue
<component
  :is="componentMap[item.showType]"
  :settings="item.settings"
></component>
<component
  :is="componentMap[item.showType]"
  :settings="item.settings"
></component>

自动导入模块

js
//import.meta.glob用于实现基于模式的文件导入,类似于文件系统的模式匹配
//例如 *.vue来一次性导入多个文件。这通常用于动态加载模块或组件。
import.meta.glob('/src/components/**/*.vue')
//import.meta.glob用于实现基于模式的文件导入,类似于文件系统的模式匹配
//例如 *.vue来一次性导入多个文件。这通常用于动态加载模块或组件。
import.meta.glob('/src/components/**/*.vue')

提示

  1. import.meta.glob返回一个函数,该函数接受一个字符串参数,该参数是一个模式,用于匹配文件路径。
  2. 返回的函数返回一个对象,该对象的键是匹配的文件路径,值是一个函数,该函数返回一个Promise,该Promise解析为模块的导出。
  3. import.meta.globEager返回一个对象,该对象的键是匹配的文件路径,值是模块的导出。
  4. import.meta.globEager返回的对象是静态的,不会在运行时更新。

import.meta.glob原理

  1. 模式定义:你指定一个匹配模式,如 import.meta.glob('../components/*.vue'),来匹配所有在 components 目录下的 Vue 组件。
  2. 编译时转换:在构建过程中,基于这个模式,构建工具(如 Vite)会分析并识别出符合模式的所有文件。
  3. 生成动态导入语句:对于每个匹配的文件,import.meta.glob 会生成一个返回 Promise 的函数,该函数在调用时会动态导入相应的模块。
  4. 惰性加载:由于每个导入都是通过 Promise 实现的,模块只会在你实际调用这个函数时才被加载。这使得初始包大小可以保持较小,同时允许按需加载更多的内容

常见例子

js
// 一次性导入多个文件
const modules = import.meta.glob('../components/*.vue')
//导入某个文件
const module = import.meta.glob('../components/HelloWorld.vue')
//导入某个文件夹下的所有文件
const modules = import.meta.glob('../components/*.vue')
//导入某个文件夹下的所有文件夹下的所有文件
const modules = import.meta.glob('../components/**/*.vue')
// 一次性导入多个文件
const modules = import.meta.glob('../components/*.vue')
//导入某个文件
const module = import.meta.glob('../components/HelloWorld.vue')
//导入某个文件夹下的所有文件
const modules = import.meta.glob('../components/*.vue')
//导入某个文件夹下的所有文件夹下的所有文件
const modules = import.meta.glob('../components/**/*.vue')
js
const modules = import.meta.glob('./components/**/*.vue')
for (const path in modules) {
  modules[path]().then((mod) => {
    // 处理每个模块
  })
}
const modules = import.meta.glob('./components/**/*.vue')
for (const path in modules) {
  modules[path]().then((mod) => {
    // 处理每个模块
  })
}
js
const modules = import.meta.globEager('./components/**/*.vue')
for (const path in modules) {
  const component = modules[path]
  // 处理每个模块
}
const modules = import.meta.globEager('./components/**/*.vue')
for (const path in modules) {
  const component = modules[path]
  // 处理每个模块
}
js
const components = import.meta.glob('./components/**/*.vue')
Object.entries(components).forEach(([path, defineAsyncComponent]) => {
  const componentName = path
    .split('/')
    .pop()
    .replace(/\.\w+$/, '')
  app.component(componentName, defineAsyncComponent())
})
const components = import.meta.glob('./components/**/*.vue')
Object.entries(components).forEach(([path, defineAsyncComponent]) => {
  const componentName = path
    .split('/')
    .pop()
    .replace(/\.\w+$/, '')
  app.component(componentName, defineAsyncComponent())
})
js
const routes = Object.keys(import.meta.glob('../views/*.vue')).map((path) => {
  return {
    path: path.replace(/..\/views|\.vue/g, ''),
    component: () => import(path)
  }
})
const routes = Object.keys(import.meta.glob('../views/*.vue')).map((path) => {
  return {
    path: path.replace(/..\/views|\.vue/g, ''),
    component: () => import(path)
  }
})

Vue项目(Webpack)

代码

js
const modulesFiles = require.context(
  '@/views/pc/homeSet/components/module',
  false,
  /\.vue$/
)

const components = modulesFiles.keys().reduce((components, modulePath) => {
  const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
  components[moduleName] = () =>
    import(`@/views/pc/homeSet/components/module/${moduleName}.vue`)
  return components
}, {})
const modulesFiles = require.context(
  '@/views/pc/homeSet/components/module',
  false,
  /\.vue$/
)

const components = modulesFiles.keys().reduce((components, modulePath) => {
  const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
  components[moduleName] = () =>
    import(`@/views/pc/homeSet/components/module/${moduleName}.vue`)
  return components
}, {})
vue
computed: { currentComponent() { return
components[`module${specialTypes[this.moduleObj.showType] ||
this.moduleObj.showType}`]; } }
computed: { currentComponent() { return
components[`module${specialTypes[this.moduleObj.showType] ||
this.moduleObj.showType}`]; } }

自动导入模块

require.context() 是一个Webpack特有的特性,用于创建一个上下文,通过它可以告诉Webpack在构建过程中应该动态地从一个目录中包含哪些文件。这个功能通常在需要动态地加载一组模块时使用,例如自动加载某个目录下的所有测试文件或组件。这样做可以减少手动导入每个文件的需要,简化代码并提高可维护性。

require.context用法

  • 基本用法
js
var context = require.context(
  directory,
  (useSubdirectories = false),
  (regExp = /^\.\//)
)
var context = require.context(
  directory,
  (useSubdirectories = false),
  (regExp = /^\.\//)
)
  • 参数说明
  • directory:说明需要检索的目录
  • useSubdirectories:是否检索子目录
  • regExp: 匹配文件的正则表达式
  • 返回值 require.context() 返回一个(require)函数,这个函数可以接受一个参数:请求的文件的路径。这个函数有三个属性:
html
resolve:是一个函数,它返回请求被解析后得到的模块id
keys:是一个函数,它返回一个数组,包含所有可能被上下文模块处理的模块的路径
id:是执行此上下文模块的模块id
resolve:是一个函数,它返回请求被解析后得到的模块id
keys:是一个函数,它返回一个数组,包含所有可能被上下文模块处理的模块的路径
id:是执行此上下文模块的模块id