前端动态导入(import.meta.glob) 的实用场景和详细示例

import.meta.glob 的各种实用场景和详细示例如下:

1. Vue 组件自动注册系统

typescript 复制代码
// components/index.ts
const components = import.meta.glob('./**/*.vue', { eager: true })

export function registerGlobalComponents(app) {
  Object.entries(components).forEach(([path, module]) => {
    // 提取组件名称
    // 例如:'./Button/index.vue' -> 'Button'
    //      './Form/Input.vue' -> 'FormInput'
    const componentName = path
      .split('/')
      .filter(segment => segment !== '.' && !segment.includes('.vue'))
      .join('')
    
    app.component(componentName, module.default)
  })
}

// 使用
import { createApp } from 'vue'
import { registerGlobalComponents } from './components'

const app = createApp(App)
registerGlobalComponents(app)

2. 高级路由配置系统

typescript 复制代码
// router/index.ts
const layouts = import.meta.glob('../layouts/*.vue', { eager: true })
const pages = import.meta.glob('../pages/**/*.vue')

// 处理布局组件
const layoutComponents = Object.entries(layouts).reduce((acc, [path, module]) => {
  const layoutName = path.match(/\.\.\/layouts\/(.*)\.vue$/)?.[1]
  if (layoutName) {
    acc[layoutName] = module.default
  }
  return acc
}, {})

// 生成路由配置
const routes = Object.entries(pages).map(([path, component]) => {
  // 从文件路径提取路由信息
  const routePath = path
    .replace('../pages', '')
    .replace('.vue', '')
    .replace(/\/index$/, '/')
    
  // 从文件名提取元数据
  const segments = path.split('/')
  const fileName = segments[segments.length - 1].replace('.vue', '')
  
  // 判断是否需要认证(例如:文件名以 Auth 开头)
  const requiresAuth = fileName.startsWith('Auth')
  
  // 确定使用的布局(可以基于目录结构)
  const layout = segments.includes('admin') ? 'AdminLayout' : 'DefaultLayout'
  
  return {
    path: routePath,
    component,
    meta: {
      requiresAuth,
      layout: layoutComponents[layout]
    }
  }
})

3. 多语言国际化系统

typescript 复制代码
// i18n/index.ts
const messages = import.meta.glob('./locales/**/*.json', {
  eager: true,
  as: 'string'
})

interface LocaleMessages {
  [locale: string]: {
    [key: string]: any
  }
}

// 处理语言文件
const i18nMessages: LocaleMessages = Object.entries(messages).reduce((acc, [path, content]) => {
  // 提取语言代码和命名空间
  // 例如:./locales/zh-CN/common.json -> { locale: 'zh-CN', namespace: 'common' }
  const match = path.match(/\.\/locales\/([^/]+)\/([^.]+)\.json$/)
  if (match) {
    const [, locale, namespace] = match
    if (!acc[locale]) {
      acc[locale] = {}
    }
    
    // 解析 JSON 内容并按命名空间存储
    acc[locale][namespace] = JSON.parse(content)
  }
  return acc
}, {})

// 创建 i18n 实例
import { createI18n } from 'vue-i18n'

export const i18n = createI18n({
  messages: i18nMessages,
  legacy: false,
  locale: 'zh-CN',
  fallbackLocale: 'en'
})

4. 动态 API 接口管理

typescript 复制代码
// api/index.ts
const apiModules = import.meta.glob('./modules/*.ts', { eager: true })

interface ApiDefinition {
  path: string
  method: 'GET' | 'POST' | 'PUT' | 'DELETE'
  auth?: boolean
}

// 收集所有 API 定义
const apiDefinitions = Object.entries(apiModules).reduce((acc, [path, module]) => {
  const namespace = path.match(/\.\/modules\/(.*)\.ts$/)?.[1]
  if (namespace) {
    acc[namespace] = module.default
  }
  return acc
}, {})

// 创建请求实例
import axios from 'axios'

const instance = axios.create({
  baseURL: '/api'
})

// 生成 API 方法
export const api = Object.entries(apiDefinitions).reduce((acc, [namespace, definitions]) => {
  acc[namespace] = {}
  
  Object.entries(definitions).forEach(([key, def]: [string, ApiDefinition]) => {
    acc[namespace][key] = async (data?: any) => {
      const config = {
        url: def.path,
        method: def.method,
        ...(def.method === 'GET' ? { params: data } : { data })
      }
      
      if (def.auth) {
        // 添加认证信息
        config.headers = {
          Authorization: `Bearer ${localStorage.getItem('token')}`
        }
      }
      
      return instance(config)
    }
  })
  
  return acc
}, {})

5. 自动加载 Vuex/Pinia 模块

typescript 复制代码
// store/index.ts
const storeModules = import.meta.glob('./modules/*.ts', { eager: true })

// Vuex 示例
import { createStore } from 'vuex'

const modules = Object.entries(storeModules).reduce((acc, [path, module]) => {
  const moduleName = path.match(/\.\/modules\/(.*)\.ts$/)?.[1]
  if (moduleName) {
    acc[moduleName] = module.default
  }
  return acc
}, {})

export const store = createStore({
  modules
})

// Pinia 示例
const stores = Object.entries(storeModules).reduce((acc, [path, module]) => {
  const storeName = path.match(/\.\/modules\/(.*)\.ts$/)?.[1]
  if (storeName) {
    acc[storeName] = module.default
  }
  return acc
}, {})

// 自动注册 store
export function registerStores(app) {
  const pinia = createPinia()
  app.use(pinia)
  
  Object.entries(stores).forEach(([name, store]) => {
    pinia.use(store)
  })
}

6. 自动注册指令系统

typescript 复制代码
// directives/index.ts
const directives = import.meta.glob('./modules/*.ts', { eager: true })

export function registerDirectives(app) {
  Object.entries(directives).forEach(([path, module]) => {
    const directiveName = path.match(/\.\/modules\/(.*)\.ts$/)?.[1]
    if (directiveName) {
      // 转换指令名称为 kebab-case
      // 例如:clickOutside -> v-click-outside
      const kebabName = directiveName
        .replace(/([A-Z])/g, '-$1')
        .toLowerCase()
        .replace(/^-/, '')
      
      app.directive(kebabName, module.default)
    }
  })
}

这些示例展示了 import.meta.glob 在实际项目中的高级应用。每个示例都包含了:

  • 文件组织结构的建议
  • 命名规范的处理
  • 类型安全的考虑
  • 实际业务场景的适配

通过这些模式,可以构建出更加模块化、可维护的项目结构。

相关推荐
酷小洋20 分钟前
Ajax基础
前端·ajax·okhttp
小妖66621 分钟前
vue2 provide 后 inject 数据不是响应式的,不实时更新
java·服务器·前端
是代码侠呀1 小时前
HTTP 的发展史:从前端视角看网络协议的演进
前端·网络协议·http·开源·github·github star·github 加星
heyCHEEMS1 小时前
Vue 两种导航方式
前端·javascript·vue.js
我是哈哈hh1 小时前
【vue】vuex实现组件间数据共享 & vuex模块化编码 & 网络请求
前端·javascript·vue.js·前端框架·网络请求·vuex·模块化
想睡好2 小时前
圆角边框 盒子阴影 文字阴影
前端·css·html
fei_sun2 小时前
【数据结构】子串、前缀
java·前端·数据结构
zfyljx2 小时前
2048 html
前端·css·html
帮帮志2 小时前
如何启动vue项目及vue语法组件化不同标签应对的作用说明
前端·javascript·vue.js
森哥的歌2 小时前
深入解析Vue3中ref与reactive的区别及源码实现
前端·javascript·vue.js