🧑💻 寫在開頭
點贊 + 收藏 === 學會🤣🤣🤣
起因
週五快下班,老闆過來看權限配置頁面。
"這個每次都要手動輸路徑?"
"對,現在是這樣。"我打開給他看:
角色:運營專員 路由路徑:[手動輸入] /user/list 組件路徑:[手動輸入] @/views/user/List.vue
"上次運營配錯了,/user/list 寫成 /user/lists,頁面打不開找了半天。能不能做個下拉框,直接選?"
我想了想:"可以,但得先有個頁面列表。"
"那就搞一個,現在頁面這麼多,手動輸容易出錯。"
確實,項目現在幾十個頁面,每次配置權限都要翻代碼找路徑,複製粘貼,還擔心複製錯。
解決辦法
週末琢磨了一下,其實就是缺個"頁面清單"。views 目錄下都是頁面文件,掃描一遍不就有了?
寫了個 Node 腳本,自動掃描 views 目錄,生成路由映射表。配置權限的時候下拉框選,還能搜索。
實現
兩步:掃描文件 + 生成映射。
掃描 .vue 文件
function getAllVueFiles(dir, filesList = []) {
const files = fs.readdirSync(dir);
files.forEach((file) => {
const filePath = path.join(dir, file);
if (fs.statSync(filePath).isDirectory()) {
getAllVueFiles(filePath, filesList); // 遞歸子目錄
} else if (file.endsWith(".vue")) {
filesList.push(filePath); // 收集 .vue 文件
}
});
return filesList;
}
生成映射文件
function start() {
const viewsDir = path.resolve(__dirname, "../views");
let files = getAllVueFiles(viewsDir);
// 兼容 Windows 路徑
files = files.map(item => item.replace(/\\/g, "/"));
// 拼接成 import 映射
let str = "";
files.forEach(item => {
let n = item.replace(/.*src\//, "@/");
str += `"${n}":()=>import("${n}"),\r\n`;
});
// 寫入文件
fs.writeFileSync(
path.resolve(__dirname, "../router/all.router.js"),
`export const ROUTERSDATA = {\n${str}}`
);
}
最後生成的文件大概是這樣:
// src/router/all.router.js
export const ROUTERSDATA = {
"@/views/Home.vue": () => import("@/views/Home.vue"),
"@/views/About.vue": () => import("@/views/About.vue"),
"@/views/user/List.vue": () => import("@/views/user/List.vue"),
}
怎麼用
權限配置頁面
<template>
<el-select
v-model="selectedRoute"
filterable
placeholder="搜索並選擇頁面">
<el-option
v-for="(component, path) in ROUTERSDATA"
:key="path"
:label="path"
:value="path">
{{ path }}
</el-option>
</el-select>
</template>
<script setup>
import { ROUTERSDATA } from '@/router/all.router.js'
// 後台返回的權限路由配置
const permissionRoutes = [
{ path: '/user/list', component: '@/views/user/List.vue' },
{ path: '/order/list', component: '@/views/order/List.vue' }
]
// 直接從映射表取組件
const routes = permissionRoutes.map(route => ({
path: route.path,
component: ROUTERSDATA[route.component] // 這裏直接用
}))
</script>
好處:
- 下拉框自動包含所有頁面
- 支持搜索,輸入 "user" 就能找到所有用户相關頁面
- 新加頁面自動出現在列表裏
動態路由
後台返回權限配置,前端從映射表取組件:
function generateRoutes(backendConfig) {
return backendConfig.map(item => ({
path: item.path,
component: ROUTERSDATA[item.component] // 直接用
}))
}
效果
週一把代碼提上去,改了權限配置頁面:
<!-- 配置頁面 -->
<el-select v-model="route" filterable placeholder="搜索頁面">
<el-option
v-for="(component, path) in ROUTERSDATA"
:key="path"
:label="path"
:value="path" />
</el-select>
老闆過來試了一下,在下拉框輸入 "user" 就搜到所有用户相關頁面。
"嗯,這個好用。新加頁面也會自動出現在這裏吧?"
"對,每次啓動項目會自動掃描。"
"行,那就這樣。"
後來發現還有些意外收穫:
- 新人看這個映射表就知道項目有哪些頁面
- 後台只存路徑字符串,數據庫乾淨
- 順帶解決了手動 import 幾十個路由的問題
在 package.json 加個腳本:
{
"scripts": {
"dev": "node src/start/index.js && vite"
}
}
每次 npm run dev 會先掃描 views 目錄,生成最新的映射表。
完整代碼
// src/start/index.js
const fs = require("fs");
const path = require("path");
function getAllVueFiles(dir, filesList = []) {
const files = fs.readdirSync(dir);
files.forEach((file) => {
const filePath = path.join(dir, file);
const stat = fs.statSync(filePath);
if (stat.isDirectory()) {
getAllVueFiles(filePath, filesList);
} else if (file.endsWith(".vue")) {
filesList.push(filePath);
}
});
return filesList;
}
function start() {
console.log("[自動獲取全部可顯示頁面]");
const viewsDir = path.resolve(__dirname, "../views");
let files = getAllVueFiles(viewsDir);
// 統一路徑分隔符,兼容 Windows 反斜槓
files = files.map((item) => item.replace(/\\/g, "/"));
let str = "";
// 構造 import 映射:"@/views/xxx.vue": ()=>import("@/views/xxx.vue")
files.forEach((item) => {
let n = item.replace(/.*src\//, "@/");
str += `"${n}":()=>import("${n}"),\r\n`;
});
const routerFilePath = path.resolve(__dirname, "../router/all.router.js");
// 將映射寫入路由聚合文件,供路由動態引用
fs.writeFileSync(
routerFilePath,
`
export const ROUTERSDATA = {
${str}
}`,
);
console.log("[./src/router/all.router.js 寫入]");
}
start();
注意事項
記得把生成的 src/router/all.router.js 加到 .gitignore,畢竟是自動生成的文件,沒必要提交。
# .gitignore src/router/all.router.js
後來
用了一個多月,運營配置權限再也沒出過錯。上週老闆説:"這個功能不錯,其他項目也加上。"
代碼其實挺簡單的,但確實解決了問題。