路由自动导入
路由 routes 目录结构为
- src
- routes
- index.js
- modules
- layout
- index.js
- main
- index.js
- layout
在layout/index.js里面的路由写法
// routes/modules/layout/index.js
import Layout from '@/views/Layout/Layout.vue'
import Home from '@/views/Layout/Home.vue'
import Cart from '@/views/Layout/Cart.vue'
import Category from '@/views/Layout/Category.vue'
import MySpace from '@/views/Layout/MySpace.vue'
export default [
{
path: '/',
redirect: 'home',
component: Layout,
children: [
{path:'/home', component: Home},
{path:'/category', component: Category},
{path:'/cart', component: Cart},
{path:'/myspace', component: MySpace}
]
},
]
将路由按业务逻辑和功能划分分成模块后,就所有模块的路由都进行拆分到了 modules/
文件夹下,每个文件中只需要导出当前模块用到的路由配置。这个时候我们只需要导入所有模块的内容汇总到 index.js
中即可
但是我们会发现我们在 index.js
中会反复的进行 import ... from ...
导入所有配置的路由模块,模块一多那么这些的 import
语句也就越多。
所以就需要用到路由的自动导入。由于项目用的是vite,所以就使用vite自带的 import.meta.glob
批量导入路由。
首先,定义路径模式,常见的路径模式有
- 匹配某个文件夹下的所有
.js
文件:./path/*.js
- 匹配某个文件夹及其子文件夹下的所有
.vue
文件:./path/**/*.vue
- 排除某个文件夹下的某个文件:
./path/!(*.md)
再调用 import.meta.glob 方法来导入匹配的模块,下面是导入同一文件路径 routes 下 modules 文件夹及其嵌套的全部子文件夹下的所有 index.js 文件。
该方法返回一个对象,其中每个键都是匹配到的模块路径,每个 js 文件中导出的内容(包括 default),在这里是路由对象。
// routes/index.js
// route模块自动导入
const routeModules = import.meta.glob('./modules/*/*.js', { eager: true })
// 通过 reduce 去搜集所有的模块的导出内容
const configRoutes = Object.keys(routeModules).reduce((routes, filepath) => {
// 导出的对象中有一个属性:default,可以获取到默认导出的所有内容
const value = routeModules[filepath].default;
// 我们判断导出的是不是数组,是则进行拓展解构
if (Array.isArray(value)) {
routes.push(...value);
} else {
// 否则直接加到routes中
routes.push(value);
}
return routes;
}, []);
// 直接导出所有模块配置的路由
export const router = createRouter({
history: createWebHistory(),
routes: configRoutes
})
export default router
所得到的 configRoutes 是一个数组包对象,其中数组中的对象就代表了每一个路由:
API自动导入
同样将API按照业务逻辑划分为模块,但这就需要在最外层的index.js中会反复的进行 import ... from ...
导入所有模块。所以我们同样利用 vite 自带的 import.meta.glob 批量导入API。
接口 apis ,目录结构为
- src
- apis
- index.js
- modules
- user
- index.js
- user
apis文件user/index.js的文件结构和内容为:
import { request } from '../../request'
export default {
login: async query => {
return await request('post', '/v1_0/authorizations', query)
}
}
第一步,先在request.js中引入axios,并设置默认请求拦截器和响应拦截器:
// request.js
import axios from 'axios'
import Storage from '@/storage/index.js'
const http = axios.create({
baseURL: 'http://geek.itheima.net',
timeout: 5000
})
// 添加请求拦截器
http.interceptors.request.use((config)=> {
// 在config中的请求头注入token数据
const token = Storage.user.getToken()
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
}, (error)=> {
return Promise.reject(error)
})
// 添加响应拦截器
http.interceptors.response.use((response)=> {
// 2xx 范围内的状态码都会触发该函数。
// 对响应数据做点什么
return response.data
}, (error)=> {
// 超出 2xx 范围的状态码都会触发该函数。
// 对响应错误做点什么
return Promise.reject(error)
})
const request = (method, url, query) => {
return http({
method,
url,
data: query
})
}
export { request }
第二步,在index.js文件里面通过调用 import.meta.glob 方法来导入匹配的模块,导入同一文件路径 apis 下 modules 文件夹及其嵌套的全部子文件夹下的所有 index.js 文件
// api模块自动导入
const apiModules = import.meta.glob('./modules/*/index.js', { eager: true })
const Service = {}
Object.keys(apiModules).forEach(path => {
const key = path.split('/')[2]
Service[key] = apiModules[path].default
})
export default Service
apiModules的键还是路径名,值每个模块中 export 的内容,在这里是包含着 api 函数的对象。最终得到的 Service 是一个对象,键为模块名称,值为模块对应的包含 api 函数的对象。
所以在页面和组件中调用 api 可以
- 通过 导入 Service :import Service from '@/apis/index.js’;
- 然后在 js 代码中 await Service.user.xxx(query) 来调用服务端接口