前端路由核心是拦截URL变化、不刷新页面、按路径匹配渲染视图;需用history.pushState和popstate事件实现,避免hashchange,注意SEO、滚动复位、标题更新等细节。

JavaScript 实现前端路由,核心不是“写个跳转函数”,而是**拦截 URL 变化、不刷新页面、按路径匹配渲染对应视图**。现代 SPA 路由本质是 history.pushState + window.addEventListener('popstate') 的组合,手动实现几行就能跑通,但真实项目中必须处理好路由嵌套、参数解析、滚动复位、动态加载等细节。
如何用原生 JavaScript 手动实现最简路由
适合学习原理或超轻量场景(比如嵌入式面板、微前端子应用)。关键点在于:不触发页面刷新,靠浏览器历史 API 操作地址栏,再监听变化来切换内容。
- 用
history.pushState()替代window.location.href = '/xxx',避免刷新 - 监听
popstate事件捕获后退/前进,而不是只监听hashchange(后者兼容性好但 URL 带#) - 路由匹配建议用正则或
URLPattern(Chrome 110+),避免简单===字符串比对(如/user/123和/user/456都该命中/user/:id) - 示例片段:
function route(path, handler) { if (location.pathname === path) handler(); } window.addEventListener('popstate', () => route('/about', renderAbout)); history.pushState({}, '', '/about');
为什么不要自己封装复杂路由库
手写基础逻辑没问题,但一旦涉及嵌套路由、懒加载、路由守卫、类型安全、SSR 兼容,维护成本会指数上升。真实项目中,99% 场景应直接选用成熟方案。
-
React Router v6的createBrowserRouter内置了 loader、errorElement、useNavigate等完整生命周期,且与并发渲染兼容 -
Vue Router 4的createRouter({ history: createWebHistory() })默认启用 HTML5 History 模式,无需 Nginx 配置 fallback 就能支持深层路由(前提是服务端已配好) - 自己实现时容易忽略
scrollRestoration: 'manual'导致后退时页面卡在底部,或忘记调用history.scrollRestoration = 'auto'恢复默认行为
history.pushState 和 hash 路由的实际区别
不是“哪个更高级”,而是部署约束和 SEO 行为不同。选错会导致线上 404 或搜索引擎抓不到内容。
立即学习“Java免费学习笔记(深入)”;
-
pushState路由(/user/123):需服务端配置 fallback(如 Nginx 返回index.html),否则直接访问深层链接会 404;但 URL 干净,利于 SEO -
hash路由(/#user/123):完全由前端控制,无需服务端配合;但搜索引擎可能忽略#后内容,且location.hash不触发popstate,得监听hashchange - 注意:调用
pushState后,location.pathname立即更新;而修改location.hash不会触发页面刷新,但会触发hashchange事件
SPA 路由最容易被忽略的三个细节
这些点不报错,但上线后用户感知极差,且很难被测试覆盖。
-
document.title不随路由自动更新——必须在路由切换回调里显式设置,否则所有页面标题都是初始值 - 路由切换后焦点未重置——屏幕阅读器用户可能卡在上一页末尾,应调用
document.body.focus({ preventScroll: true })或聚焦到主内容区 - 异步组件加载失败时没兜底——
React.lazy+Suspense必须配Fallback,否则白屏;Vue 的defineAsyncComponent也要设errorComponent
真正难的从来不是“怎么跳转”,而是让每次跳转都像原生页面一样自然:URL 正确、标题正确、焦点正确、滚动位置合理、错误可感知。这些细节堆起来,才是用户说“这网站真快”的原因。











