系列文章目录《JavaScript 基础与进阶笔记》前期偏基础巩固与常见面试点后续进入闭包、异步、工程化等进阶主题第 01 篇数据类型与类型判断第 02 篇变量声明与作用域第 03 篇闭包与高阶函数第 04 篇函数工厂第 05 篇this 指向与绑定第 06 篇原型与原型链第 07 篇类与继承第 08 篇JS 执行机制与异步队列第 09 篇数组常用方法第 10 篇字符串算法第 11 篇常见手写题合集上第 12 篇常见手写题合集下第 13 篇Promise 与 async/await第 14 篇数据结构基础第 15 篇垃圾回收与内存第 16 篇DOM 基础全面解析第 17 篇DOM 性能与渲染第 18 篇DOM 交互补充第 19 篇DOM 实战案例第 20 篇CSS 布局与可视化高频第 21 篇移动端与 viewport第 22 篇BOM 核心对象第 23 篇前端路由原理本文文章目录系列文章目录前言一、什么是前端路由二、Hash 路由 vs History 路由三、Hash 路由最小实现四、History 路由最小实现五、History 刷新 404 的原因与解决5.1 原因5.2 解决fallback 到入口六、路由匹配与动态参数七、Vue Router 速览7.1 两种 History 工厂7.2 路由懒加载7.3 路由守卫鉴权7.4 嵌套路由与全局 4047.5 与 KeepAlive、Transition 的关系八、Hash vs History 选型口诀九、易混淆点归纳十、思考与练习总结前言第 22 篇讲了history.pushState与popstate本篇把它们放进SPA 前端路由的完整图景Hash 与 History 两种模式、简易手写实现、刷新 404怎么解决以及 Vue Router 中的守卫与懒加载。面试常问「两种路由区别」「为什么 History 刷新 404」「pushState 会不会触发 popstate」。一、什么是前端路由单页应用SPA只有一个 HTML 入口如index.html页面「跳转」不整页刷新而是JS 换组件。前端路由根据当前 URLhash 或 path匹配路由表渲染对应视图组件。用户点击菜单 / 改 URL → 路由匹配path params query → 渲染组件可懒加载 chunk → 可选守卫鉴权、改标题、埋点与后端路由的区别后端路由决定哪个 API/哪个 HTML 文件前端路由决定同一 SPA 里显示哪个页面组件两者各管一层。二、Hash 路由 vs History 路由Hash 模式History 模式URL 形态https://a.com/#/user/1https://a.com/user/1依据location.hash#后内容location.pathname监听hashchangepopstate前进/后退 主动pushState后自 render发请求#及之后不发给服务器刷新时浏览器请求完整 path服务端配置一般不需要需fallback 到 index.html兼容性极好IE8需 History APISEO/美观URL 带#URL 更干净选型内网/中后台 Hash 够用对外 C 端、要分享链接、要 SEO 倾向History 服务端 fallback。三、Hash 路由最小实现constroutes{/:()h1首页/h1,/about:()h1关于/h1,/user/:id:(params)h1用户${params.id}/h1,};functionmatchRoute(hash){constpathhash||/;constuserMatchpath.match(/^\/user\/(\w)$/);if(userMatch)return{handler:routes[/user/:id],params:{id:userMatch[1]}};return{handler:routes[path],params:{}};}functionrender(){consthashlocation.hash.slice(1);/* 去掉 # */const{handler,params}matchRoute(hash);constappdocument.getElementById(app);app.innerHTMLhandler?handler(params):h1404/h1;}window.addEventListener(hashchange,render);render();/* 首屏 *//* 编程式跳转 */functionnavigate(path){location.hashpath;/* 触发 hashchange */}要点改location.hash会触发hashchange在回调里match render即可。四、History 路由最小实现constroutes{/:()h1首页/h1,/about:()h1关于/h1,};functionrender(pathname){consthandlerroutes[pathname];document.getElementById(app).innerHTMLhandler?handler():h1404/h1;}functionnavigate(path){history.pushState(null,,path);render(path);/* pushState 不触发 popstate必须手动 render */}window.addEventListener(popstate,(){render(location.pathname);/* 浏览器前进/后退 */});render(location.pathname);/* 首屏 */与第 22 篇衔接pushState/replaceState改 URL不刷新、不触发popstatepopstate仅前进/后退或history.back()等触发因此 SPA主动跳转 pushState 自己 render后退 popstate render五、History 刷新 404 的原因与解决5.1 原因用户访问https://a.com/user/1后刷新浏览器向服务器请求/user/1这个真实路径。若服务器只有静态文件、没有该文件 →404。Hash 模式刷新时请求的是/或/index.html#/user/1不会发到服务端故无此问题。5.2 解决fallback 到入口所有非静态资源的路径都返回index.html仍由前端路由解析 path。# Nginx location / { try_files $uri $uri/ /index.html; }// Express connect-history-api-fallbackconsthistoryrequire(connect-history-api-fallback);app.use(history({index:/index.html}));app.use(express.static(dist));注意API 路径如/api/*应代理到后端不要被 fallback 吞掉。六、路由匹配与动态参数路由表常见字段字段含义path路径如/user/:idname命名路由方便router.push({ name: User })component对应组件meta元信息鉴权、标题等children嵌套路由动态参数/user/:id→params.id查询参数/list?page2→query.pageURLSearchParams或框架封装七、Vue Router 速览7.1 两种 History 工厂import{createRouter,createWebHistory,createWebHashHistory}fromvue-router;constroutercreateRouter({history:createWebHistory(),/* History 模式需服务端 fallback */// history: createWebHashHistory(), /* Hash 模式 */routes:[{path:/,component:()import(./views/Home.vue)},{path:/user/:id,component:()import(./views/User.vue),meta:{auth:true}},],});7.2 路由懒加载{path:/order,component:()import(./views/Order.vue),/* 独立 chunk访问时才加载 */}首屏只加载当前路由 chunk其余按需下载见系列代码分割篇。7.3 路由守卫鉴权router.beforeEach((to,from){consttokenlocalStorage.getItem(token);if(to.meta.auth!token)return/login;/* Vue Router 4return 路径即重定向 */});router.afterEach((to){document.titleto.meta.title??App;});守卫类型一览守卫作用域典型用途beforeEach全局登录校验、权限beforeResolve全局异步组件加载后、确认进入页面前的最后一关beforeEnter单条路由仅该路由进入前校验onBeforeRouteLeave组件内离开前确认未保存表单等onBeforeRouteUpdate组件内同组件、仅 params 变化时/* 路由独享守卫 */{path:/admin,component:Admin,beforeEnter:(){if(!hasRole(admin))return/403;},}/* 组件内 — 离开确认 */import{onBeforeRouteLeave}fromvue-router;onBeforeRouteLeave((){if(hasUnsaved)returnconfirm(未保存确定离开);});beforeResolve在beforeEach与组件内守卫都通过、懒加载组件解析完成后触发适合做埋点、关 loading等「确定要进入该页」的逻辑。7.4 嵌套路由与全局 404嵌套父路由渲染布局子路由渲染在父组件的router-view里可多层。constroutes[{path:/,component:Layout,children:[{path:,component:Home},/* / */{path:user/:id,component:User},/* /user/1 */],},];!-- Layout.vue -- template header导航/header router-view / /template全局 404放在路由表最后匹配所有未命中路径。{path:/:pathMatch(.*)*,name:NotFound,component:NotFound},7.5 与 KeepAlive、Transition 的关系KeepAlive包在router-view外可缓存已访问过的路由组件返回时保留表单/滚动常与onBeforeRouteLeave配合离开前是否允许丢弃状态。Transition包在router-view外路由切换时做过场一般给router-view加:keyroute.path才能正确触发 enter/leave。二者完整用法见 Vue 专题本篇只说明与路由出口的挂载关系。八、Hash vs History 选型口诀需求建议快速上线、无运维改 NginxHashURL 美观、分享链接History fallback强 SEO、SSRHistory Nuxt/SSR本篇不展开只改前端、后端不管Hash更省事九、易混淆点归纳Hash 的#后不请求服务器History 的path 会请求服务器。History 刷新 404→ 服务端try_files / fallback不是前端 bug。pushState不触发popstate手动跳转后要自己更新视图。前端路由 ≠ 后端 API 路由。Hash 用hashchangeHistory 用popstate pushState 自 render。路由懒加载减首屏体积发版后 chunk 404 需错误恢复见面试笔记项目难点。十、思考与练习1.Hash 模式为什么一般不需要服务端配合解析#及之后不会发给服务器请求始终是入口 HTML由前端读 hash 渲染。2.History 模式下用户刷新/dashboard返回 404怎么排查解析看Nginx/网关是否对非静态路径fallback 到 index.htmlAPI 是否误被 fallback。3.代码里history.pushState({}, , /about)后页面没变为什么解析pushState 不触发 popstate也不自动换组件需在 push 后手动 render或走 Vue Router 的router.push。4.popstate在什么时候触发解析用户点前进/后退或代码history.back()/go()不是pushState 时。5.Vue Router 里() import(./Foo.vue)的作用解析路由懒加载该路由首次访问时才下载对应JS chunk减小首屏包体积。总结前端路由SPA 内按 URL匹配组件不整页刷新。Hashhashchange兼容好无需服务端URL 带#。HistorypushStatepopstate仅后退URL 美观刷新需 fallback。Vue RouterHistory 工厂、懒加载、守卫 / 嵌套 / 404KeepAlive / Transition包在router-view外。下一篇讲浏览器存储对比Cookie、localStorage、sessionStorage、IndexedDB系列第 24 篇。
前端路由原理
发布时间:2026/6/11 3:15:06
系列文章目录《JavaScript 基础与进阶笔记》前期偏基础巩固与常见面试点后续进入闭包、异步、工程化等进阶主题第 01 篇数据类型与类型判断第 02 篇变量声明与作用域第 03 篇闭包与高阶函数第 04 篇函数工厂第 05 篇this 指向与绑定第 06 篇原型与原型链第 07 篇类与继承第 08 篇JS 执行机制与异步队列第 09 篇数组常用方法第 10 篇字符串算法第 11 篇常见手写题合集上第 12 篇常见手写题合集下第 13 篇Promise 与 async/await第 14 篇数据结构基础第 15 篇垃圾回收与内存第 16 篇DOM 基础全面解析第 17 篇DOM 性能与渲染第 18 篇DOM 交互补充第 19 篇DOM 实战案例第 20 篇CSS 布局与可视化高频第 21 篇移动端与 viewport第 22 篇BOM 核心对象第 23 篇前端路由原理本文文章目录系列文章目录前言一、什么是前端路由二、Hash 路由 vs History 路由三、Hash 路由最小实现四、History 路由最小实现五、History 刷新 404 的原因与解决5.1 原因5.2 解决fallback 到入口六、路由匹配与动态参数七、Vue Router 速览7.1 两种 History 工厂7.2 路由懒加载7.3 路由守卫鉴权7.4 嵌套路由与全局 4047.5 与 KeepAlive、Transition 的关系八、Hash vs History 选型口诀九、易混淆点归纳十、思考与练习总结前言第 22 篇讲了history.pushState与popstate本篇把它们放进SPA 前端路由的完整图景Hash 与 History 两种模式、简易手写实现、刷新 404怎么解决以及 Vue Router 中的守卫与懒加载。面试常问「两种路由区别」「为什么 History 刷新 404」「pushState 会不会触发 popstate」。一、什么是前端路由单页应用SPA只有一个 HTML 入口如index.html页面「跳转」不整页刷新而是JS 换组件。前端路由根据当前 URLhash 或 path匹配路由表渲染对应视图组件。用户点击菜单 / 改 URL → 路由匹配path params query → 渲染组件可懒加载 chunk → 可选守卫鉴权、改标题、埋点与后端路由的区别后端路由决定哪个 API/哪个 HTML 文件前端路由决定同一 SPA 里显示哪个页面组件两者各管一层。二、Hash 路由 vs History 路由Hash 模式History 模式URL 形态https://a.com/#/user/1https://a.com/user/1依据location.hash#后内容location.pathname监听hashchangepopstate前进/后退 主动pushState后自 render发请求#及之后不发给服务器刷新时浏览器请求完整 path服务端配置一般不需要需fallback 到 index.html兼容性极好IE8需 History APISEO/美观URL 带#URL 更干净选型内网/中后台 Hash 够用对外 C 端、要分享链接、要 SEO 倾向History 服务端 fallback。三、Hash 路由最小实现constroutes{/:()h1首页/h1,/about:()h1关于/h1,/user/:id:(params)h1用户${params.id}/h1,};functionmatchRoute(hash){constpathhash||/;constuserMatchpath.match(/^\/user\/(\w)$/);if(userMatch)return{handler:routes[/user/:id],params:{id:userMatch[1]}};return{handler:routes[path],params:{}};}functionrender(){consthashlocation.hash.slice(1);/* 去掉 # */const{handler,params}matchRoute(hash);constappdocument.getElementById(app);app.innerHTMLhandler?handler(params):h1404/h1;}window.addEventListener(hashchange,render);render();/* 首屏 *//* 编程式跳转 */functionnavigate(path){location.hashpath;/* 触发 hashchange */}要点改location.hash会触发hashchange在回调里match render即可。四、History 路由最小实现constroutes{/:()h1首页/h1,/about:()h1关于/h1,};functionrender(pathname){consthandlerroutes[pathname];document.getElementById(app).innerHTMLhandler?handler():h1404/h1;}functionnavigate(path){history.pushState(null,,path);render(path);/* pushState 不触发 popstate必须手动 render */}window.addEventListener(popstate,(){render(location.pathname);/* 浏览器前进/后退 */});render(location.pathname);/* 首屏 */与第 22 篇衔接pushState/replaceState改 URL不刷新、不触发popstatepopstate仅前进/后退或history.back()等触发因此 SPA主动跳转 pushState 自己 render后退 popstate render五、History 刷新 404 的原因与解决5.1 原因用户访问https://a.com/user/1后刷新浏览器向服务器请求/user/1这个真实路径。若服务器只有静态文件、没有该文件 →404。Hash 模式刷新时请求的是/或/index.html#/user/1不会发到服务端故无此问题。5.2 解决fallback 到入口所有非静态资源的路径都返回index.html仍由前端路由解析 path。# Nginx location / { try_files $uri $uri/ /index.html; }// Express connect-history-api-fallbackconsthistoryrequire(connect-history-api-fallback);app.use(history({index:/index.html}));app.use(express.static(dist));注意API 路径如/api/*应代理到后端不要被 fallback 吞掉。六、路由匹配与动态参数路由表常见字段字段含义path路径如/user/:idname命名路由方便router.push({ name: User })component对应组件meta元信息鉴权、标题等children嵌套路由动态参数/user/:id→params.id查询参数/list?page2→query.pageURLSearchParams或框架封装七、Vue Router 速览7.1 两种 History 工厂import{createRouter,createWebHistory,createWebHashHistory}fromvue-router;constroutercreateRouter({history:createWebHistory(),/* History 模式需服务端 fallback */// history: createWebHashHistory(), /* Hash 模式 */routes:[{path:/,component:()import(./views/Home.vue)},{path:/user/:id,component:()import(./views/User.vue),meta:{auth:true}},],});7.2 路由懒加载{path:/order,component:()import(./views/Order.vue),/* 独立 chunk访问时才加载 */}首屏只加载当前路由 chunk其余按需下载见系列代码分割篇。7.3 路由守卫鉴权router.beforeEach((to,from){consttokenlocalStorage.getItem(token);if(to.meta.auth!token)return/login;/* Vue Router 4return 路径即重定向 */});router.afterEach((to){document.titleto.meta.title??App;});守卫类型一览守卫作用域典型用途beforeEach全局登录校验、权限beforeResolve全局异步组件加载后、确认进入页面前的最后一关beforeEnter单条路由仅该路由进入前校验onBeforeRouteLeave组件内离开前确认未保存表单等onBeforeRouteUpdate组件内同组件、仅 params 变化时/* 路由独享守卫 */{path:/admin,component:Admin,beforeEnter:(){if(!hasRole(admin))return/403;},}/* 组件内 — 离开确认 */import{onBeforeRouteLeave}fromvue-router;onBeforeRouteLeave((){if(hasUnsaved)returnconfirm(未保存确定离开);});beforeResolve在beforeEach与组件内守卫都通过、懒加载组件解析完成后触发适合做埋点、关 loading等「确定要进入该页」的逻辑。7.4 嵌套路由与全局 404嵌套父路由渲染布局子路由渲染在父组件的router-view里可多层。constroutes[{path:/,component:Layout,children:[{path:,component:Home},/* / */{path:user/:id,component:User},/* /user/1 */],},];!-- Layout.vue -- template header导航/header router-view / /template全局 404放在路由表最后匹配所有未命中路径。{path:/:pathMatch(.*)*,name:NotFound,component:NotFound},7.5 与 KeepAlive、Transition 的关系KeepAlive包在router-view外可缓存已访问过的路由组件返回时保留表单/滚动常与onBeforeRouteLeave配合离开前是否允许丢弃状态。Transition包在router-view外路由切换时做过场一般给router-view加:keyroute.path才能正确触发 enter/leave。二者完整用法见 Vue 专题本篇只说明与路由出口的挂载关系。八、Hash vs History 选型口诀需求建议快速上线、无运维改 NginxHashURL 美观、分享链接History fallback强 SEO、SSRHistory Nuxt/SSR本篇不展开只改前端、后端不管Hash更省事九、易混淆点归纳Hash 的#后不请求服务器History 的path 会请求服务器。History 刷新 404→ 服务端try_files / fallback不是前端 bug。pushState不触发popstate手动跳转后要自己更新视图。前端路由 ≠ 后端 API 路由。Hash 用hashchangeHistory 用popstate pushState 自 render。路由懒加载减首屏体积发版后 chunk 404 需错误恢复见面试笔记项目难点。十、思考与练习1.Hash 模式为什么一般不需要服务端配合解析#及之后不会发给服务器请求始终是入口 HTML由前端读 hash 渲染。2.History 模式下用户刷新/dashboard返回 404怎么排查解析看Nginx/网关是否对非静态路径fallback 到 index.htmlAPI 是否误被 fallback。3.代码里history.pushState({}, , /about)后页面没变为什么解析pushState 不触发 popstate也不自动换组件需在 push 后手动 render或走 Vue Router 的router.push。4.popstate在什么时候触发解析用户点前进/后退或代码history.back()/go()不是pushState 时。5.Vue Router 里() import(./Foo.vue)的作用解析路由懒加载该路由首次访问时才下载对应JS chunk减小首屏包体积。总结前端路由SPA 内按 URL匹配组件不整页刷新。Hashhashchange兼容好无需服务端URL 带#。HistorypushStatepopstate仅后退URL 美观刷新需 fallback。Vue RouterHistory 工厂、懒加载、守卫 / 嵌套 / 404KeepAlive / Transition包在router-view外。下一篇讲浏览器存储对比Cookie、localStorage、sessionStorage、IndexedDB系列第 24 篇。