首站登陆 發表於 2026-2-8 11:09:00

老板:能不能别手动复制路由了?我:写个脚本自动扫描

<h1 data-id="heading-0">🧑‍💻 写在开头</h1>
<p>点赞 + 收藏 === 学会🤣🤣🤣</p>
<h2 data-id="heading-0">起因</h2>
<p>周五快下班,老板过来看权限配置页面。</p>
<p>"这个每次都要手动输路径?"</p>
<p>"对,现在是这样。"我打开给他看:</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">角色:运营专员
路由路径:[手动输入] /user/list
组件路径:[手动输入] @/views/user/List.vue</pre>
</div>
<div>
<div>
<p>"上次运营配错了,<code>/user/list</code> 写成 <code>/user/lists</code>,页面打不开找了半天。能不能做个下拉框,直接选?"</p>
<p>我想了想:"可以,但得先有个页面列表。"</p>
<p>"那就搞一个,现在页面这么多,手动输容易出错。"</p>
<p>确实,项目现在几十个页面,每次配置权限都要翻代码找路径,复制粘贴,还担心复制错。</p>
<h2 data-id="heading-1">解决办法</h2>
<p>周末琢磨了一下,其实就是缺个"页面清单"。views 目录下都是页面文件,扫描一遍不就有了?</p>
<p>写了个 Node 脚本,自动扫描 <code>views</code> 目录,生成路由映射表。配置权限的时候下拉框选,还能搜索。</p>
<h2 data-id="heading-2">实现</h2>
<p>两步:扫描文件 + 生成映射。</p>
<h3 data-id="heading-3">扫描 .vue 文件</h3>
</div>
</div>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">function getAllVueFiles(dir, filesList = []) {
const files = fs.readdirSync(dir);

files.forEach((file) =&gt; {
    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;
}</pre>
</div>
<h3 data-id="heading-4">生成映射文件</h3>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">function start() {
const viewsDir = path.resolve(__dirname, "../views");
let files = getAllVueFiles(viewsDir);

// 兼容 Windows 路径
files = files.map(item =&gt; item.replace(/\\/g, "/"));

// 拼接成 import 映射
let str = "";
files.forEach(item =&gt; {
    let n = item.replace(/.*src\//, "@/");
    str += `"${n}":()=&gt;import("${n}"),\r\n`;
});

// 写入文件
fs.writeFileSync(
    path.resolve(__dirname, "../router/all.router.js"),
    `export const ROUTERSDATA = {\n${str}}`
);
}</pre>
</div>
<p>最后生成的文件大概是这样:</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">// src/router/all.router.js
export const ROUTERSDATA = {
"@/views/Home.vue": () =&gt; import("@/views/Home.vue"),
"@/views/About.vue": () =&gt; import("@/views/About.vue"),
"@/views/user/List.vue": () =&gt; import("@/views/user/List.vue"),
}</pre>
</div>
<h2 data-id="heading-5">怎么用</h2>
<h3 data-id="heading-6">权限配置页面</h3>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">&lt;template&gt;
&lt;el-select
    v-model="selectedRoute"
    filterable
    placeholder="搜索并选择页面"&gt;
    &lt;el-option
      v-for="(component, path) in ROUTERSDATA"
      :key="path"
      :label="path"
      :value="path"&gt;
      {{ path }}
    &lt;/el-option&gt;
&lt;/el-select&gt;
&lt;/template&gt;

&lt;script setup&gt;
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 =&gt; ({
path: route.path,
component: ROUTERSDATA// 这里直接用
}))
&lt;/script&gt;</pre>
</div>
<p>好处:</p>
<ul>
<li>下拉框自动包含所有页面</li>
<li>支持搜索,输入 "user" 就能找到所有用户相关页面</li>
<li>新加页面自动出现在列表里</li>
</ul>
<h3 data-id="heading-7">动态路由</h3>
<p>后台返回权限配置,前端从映射表取组件:</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">function generateRoutes(backendConfig) {
return backendConfig.map(item =&gt; ({
    path: item.path,
    component: ROUTERSDATA// 直接用
}))
}</pre>
</div>
<h2 data-id="heading-8">效果</h2>
<p>周一把代码提上去,改了权限配置页面:</p>
<div>&nbsp;
<p><img src="https://img2024.cnblogs.com/blog/2149129/202602/2149129-20260208110752406-139494798.png" alt="ScreenShot_2026-02-08_110740_493" loading="lazy"></p>
<p>&nbsp;</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">&lt;!-- 配置页面 --&gt;
&lt;el-select v-model="route" filterable placeholder="搜索页面"&gt;
&lt;el-option
    v-for="(component, path) in ROUTERSDATA"
    :key="path"
    :label="path"
    :value="path" /&gt;
&lt;/el-select&gt;</pre>
</div>
<div>
<div>
<p>老板过来试了一下,在下拉框输入 "user" 就搜到所有用户相关页面。</p>
<p>"嗯,这个好用。新加页面也会自动出现在这里吧?"</p>
<p>"对,每次启动项目会自动扫描。"</p>
<p>"行,那就这样。"</p>
<p>后来发现还有些意外收获:</p>
<ul>
<li>新人看这个映射表就知道项目有哪些页面</li>
<li>后台只存路径字符串,数据库干净</li>
<li>顺带解决了手动 import 几十个路由的问题</li>
</ul>
<p>在 <code>package.json</code> 加个脚本:</p>
</div>
</div>
</div>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">{
"scripts": {
    "dev": "node src/start/index.js &amp;&amp; vite"
}
}</pre>
</div>
<p>每次&nbsp;<code>npm run dev</code>&nbsp;会先扫描 views 目录,生成最新的映射表。</p>
<h2 data-id="heading-9">完整代码</h2>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">// src/start/index.js
const fs = require("fs");
const path = require("path");

function getAllVueFiles(dir, filesList = []) {
const files = fs.readdirSync(dir);

files.forEach((file) =&gt; {
    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) =&gt; item.replace(/\\/g, "/"));

let str = "";
// 构造 import 映射:"@/views/xxx.vue": ()=&gt;import("@/views/xxx.vue")
files.forEach((item) =&gt; {
    let n = item.replace(/.*src\//, "@/");
    str += `"${n}":()=&gt;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();</pre>
</div>
<h2 data-id="heading-10">注意事项</h2>
<p>记得把生成的&nbsp;<code>src/router/all.router.js</code>&nbsp;加到&nbsp;<code>.gitignore</code>,毕竟是自动生成的文件,没必要提交。</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;"># .gitignore
src/router/all.router.js</pre>
</div>
<h2 data-id="heading-11">后来</h2>
<p>用了一个多月,运营配置权限再也没出过错。上周老板说:"这个功能不错,其他项目也加上。"</p>
<p>代码其实挺简单的,但确实解决了问题。</p>
<div>
<h3 id="tid-D8HBxE">如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。</h3>
</div>
<p><em><img src="https://img2024.cnblogs.com/blog/2149129/202501/2149129-20250122165814748-630765389.png" alt="" loading="lazy"></em></p><br><br>
来源:https://www.cnblogs.com/smileZAZ/p/19591019
頁: [1]
查看完整版本: 老板:能不能别手动复制路由了?我:写个脚本自动扫描