一、前言
路由篇收官,把全系列遇到和没来得及展开的"事故现场"集中排雷:404 页怎么配、为什么刷新后 params 丢了、history 项目部署后白屏/404 是怎么回事。三个坑都是线上高发,本篇每坑一个"病因 + 药方"。
二、坑一:404 页面配置的正确姿势
药方:catchAll 路由,path 用正则通配:
ts
{
// ★ 语法:/:pathMatch(.*)* 意思是"任意路径任意段"
path: '/:pathMatch(.*)*',
name: 'not-found',
component: () => import('@/views/NotFoundView.vue')
}
vue
<!-- src/views/NotFoundView.vue -->
<template>
<h2>404 🔍</h2>
<p>页面去火星了:<code>{{ route.fullPath }}</code></p>
<RouterLink to="/">回首页</RouterLink>
</template>
<script setup lang="ts">
import { useRoute } from 'vue-router'
const route = useRoute()
</script>
三条规矩:
- 位置放最后:路由按声明顺序匹配,404 放前面会"接住"所有请求------有动态路由(051 篇)的项目,404 必须在动态注册完之后 addRoute
- 别用旧语法 :Vue2 的
path: '*'在 Vue Router 4 里直接报错,统一/:pathMatch(.*)* - 旧的失效路径做重定向:改版后老链接不想 404:
ts
{
path: '/about-us', // 老路径
redirect: { name: 'about' } // 301 式改道到新页面
}
三、坑二:刷新后 params 丢了
病因现场:
ts
// 列表页跳转
router.push({ name: 'user', params: { id: 1 } }) // URL 甚至没有 id!
如果 user 路由没配 path: '/user/:id',params 只活在内存 里(URL 是 /user)------页面里用没问题,F5 刷新后内存清空,params 无影无踪,页面拿空数据。
诊断口诀:params 想活过刷新,必须"写在 URL 里"。药方按场景选:
ts
// 药方 1:用动态路径,让 id 真正进 URL(首选)
router.push({ name: 'user', params: { id: 1 } })
// 路由必须配了 /user/:id → URL 是 /user/1,刷新无恙(047 篇)
// 药方 2:改用 query
router.push({ name: 'search', query: { kw: 'vue3' } })
// URL 变成 /search?kw=vue3,刷新后 route.query 还在
// 药方 3:临时状态进 Pinia/localStorage(列表筛选条件这类"非身份"数据)
// 057 篇持久化插件接管
反向坑 :router.push({ path: '/user', params: { id: 1 } }) ------path 配 params 直接被丢弃(046 篇规则),只有 name + 配了动态段的路径才吃 params。两个条件缺一个都是"看起来跳转成功了,参数却没带上"。
刷新后 route.query 没了? 检查跳转是不是用了 params 且路由没动态段------同一病根。
四、坑三:history 项目部署后白屏 / 刷新 404
病因 :history 模式的 URL(如 /user/1)是前端路由假象 。刷新/直接访问时,浏览器把 /user/1 当成真实文件路径发给服务器------服务器没有这个文件,返回 404;如果首页能开但子路由全挂、或者刷新白屏,都是这病。
药方(生产环境):Nginx 加 try_files,"找不到文件就回退给 index.html",让前端路由接管:
nginx
server {
listen 80;
root /usr/share/nginx/html;
location / {
try_files $uri $uri/ /index.html; # ★ 灵魂一行:兜底到 index.html
}
}
药方(本地验证) :不要用"直接双击 index.html"或简单静态服务器测 history 项目,npm run build 后用 npm run preview(Vite 自带 SPA 回退)验证。
临时替代 :改 hash 模式(045 篇 createWebHashHistory()),URL 带 # 但部署零配置------内网工具、快速演示可以先用 hash 顶着。
完整部署(域名、gzip、HTTPS)在 084 篇细讲,这里先把"白屏 ≠ 代码 bug,是服务器不知道把请求交给前端路由"这个病因记住。
五、附赠排雷:三个小坑快问快答
1. 跳转报"Detected an infinite redirection":守卫里改道的目标自己也触发了同样的改道逻辑(049 篇白名单问题)------检查改道终点是否被自己的规则拦截。
2. 路由切换了组件却没变:两条路由配了同一个 component 且没有动态段差异(/a 和 /b 用同一页面)------组件被复用,想要"每次重建"给 RouterView 加 :key="route.fullPath"(047 篇解法 2)。
3. base 路径部署在子目录 :应用挂在 example.com/app/ 下,访问全 404------createWebHistory('/app/')(或部署时设置 vite base),BASE_URL 就是干这个的(045 篇埋的字段这里兑现)。
六、踩坑记录(本篇是"踩坑记录本篇"------上目录清单)
- 404 用旧语法
path: '*':Vue Router 4 直接抛错,改/:pathMatch(.*)* - 404 排在路由表最前:先匹配先赢,所有页面全 404------永远放最后(动态方案下最后 addRoute)
- path + params 组合传参:params 被静默丢弃------name 配 params,path 配 query
- params 没进 URL 还指望刷新保留:内存数据活不过 F5------动态段或 query
- history 项目直接访问子路径 404/白屏:服务器缺 SPA 回退------try_files 或 preview 验证;不是前端路由配置的错
- 子目录部署没设 base:createWebHistory('/app/') 与 Vite base 双侧对齐
七、今日小结
- 404 标准姿势:
/:pathMatch(.*)*放最后(动态路由后注册);老路径用 redirect 兜住 - params 生存法则:想活过刷新必须写在 URL 里(动态段/query),path 配 params 无效
- history 白屏/404 = 服务器不认识前端路由,try_files 一行药到病除(084 篇完整部署)
至此 Vue Router 篇(045-052)完结:从建表、导航、传参、嵌套、守卫、动态注册到排雷,企业路由开发的主干全部打通。
下篇预告
数据在组件里各管各的,两个页面要共享"购物车/用户信息"怎么办?跨页面、跨组件的全局状态需要一个"数据中心"。下一篇 053 Pinia 入门------为什么它干掉了 Vuex,以及 defineStore 两种写法。