import.meta.glob 的各种实用场景和详细示例如下:
1. Vue 组件自动注册系统
// components/index.ts
const components = import.meta.glob('./**/*.vue', { eager: true })
export function registerGlobalComponents(app) {
Object.entries(components).forEach(([path, module]) => {
const componentName = path
.split('/')
.filter(segment => segment !== '.' && segment !== '') // 移除当前目录标识和空值
.map(segment => segment.replace(/\.[^.]+$/, '')) // 去除文件扩展名(如.vue)
.filter(segment => segment !== 'index') // 忽略index文件名
.join('');
app.component(componentName, module.default);
});
}
// 使用
import { createApp } from 'vue'
import { registerGlobalComponents } from './components'
const app = createApp(App)
registerGlobalComponents(app)
举例说明
- `./Form/Input.vue` → `FormInput`
- 分割路径:`['.', 'Form', 'Input.vue']`
- 过滤`.`:`['Form', 'Input.vue']`
- 去除扩展名:`['Form', 'Input']`
- 拼接结果:`FormInput`
- `./Form/Input/index.vue` → `FormInput`
- 分割路径:`['.', 'Form', 'Input', 'index.vue']`
- 过滤`.`:`['Form', 'Input', 'index.vue']`
- 去除扩展名:`['Form', 'Input', 'index']`
- 过滤`index`:`['Form', 'Input']`
- 拼接结果:`FormInput`
- **深层嵌套路径**
`./Table/Column/Item.vue` → `TableColumnItem`
- **单文件组件**
`./Header.vue` → `Header`
- **含点号的目录名**
`./my.component/Button.vue` → `mycomponentButton`
2. 高级路由配置系统
// 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]
// 例如
// path 的值为 ../layouts/MainLayout.vue
// 得到 layoutName 值为 MainLayout
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. 多语言国际化系统
// i18n/index.ts
const messages = import.meta.glob('./locales/**/*.json', {
eager: true,
})
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] = content
}
return acc
}, {})
// 创建 i18n 实例
import { createI18n } from 'vue-i18n'
export const i18n = createI18n({
messages: i18nMessages,
legacy: false,
locale: 'zh-CN',
fallbackLocale: 'en'
})
4. 动态 API 接口管理
// 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 模块
// 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. 自动注册指令系统
// 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 在实际项目中的高级应用。每个示例都包含了:
- 文件组织结构的建议
- 命名规范的处理
- 类型安全的考虑
- 实际业务场景的适配
通过这些模式,可以构建出更加模块化、可维护的项目结构。