hashchange 事件需手动触发首次渲染,监听必须用 addEventListener,首次执行要主动调用路由函数;DOM 更新应避免 innerHTML 替换,优先用 textContent 或 insertAdjacentHTML;参数解析推荐 URLPattern;pushState 必须配服务端 fallback,否则刷新即 404。

hashchange 事件监听必须手动触发首次渲染
页面加载时 hashchange 不会自动触发,哪怕 URL 已带 #/user,用户看到的仍是空白或默认视图。这是最常被跳过的初始化步骤。
- 监听写法必须是
window.addEventListener('hashchange', handler),不用window.onhashchange = handler,后者易被覆盖 - 首次执行要主动调用一次路由函数:
router()或renderPage(getCurrentPath()) -
getCurrentPath()应统一处理:对 hash 模式用location.hash.slice(1) || '/',避免直接比对location.hash === '#/home'这类硬编码 - IE8+ 支持该事件,IE7 及更早需轮询(不推荐,现代项目可忽略)
DOM 更新不能靠反复 innerHTML 替换
每次路由切换就 document.getElementById('app').innerHTML = template,看似简单,实则埋下三颗雷:事件监听器丢失、资源未释放、节点数失控。
- 优先用
textContent渲染纯文本;含 HTML 的模板,改用insertAdjacentHTML('beforeend', htmlStr)(比innerHTML更安全,不销毁已有事件) - 若需频繁更新,用
document.createDocumentFragment()缓存新节点,最后一次性挂载 - 容器本身要轻量——别套三层
<div class="wrapper"><div class="content"><main id="app">,首屏 DOM 节点建议 ≤ 500,整页 ≤ 2000 - 交互组件(如按钮、表单)必须重绑事件,或统一用事件委托:
document.getElementById('app').addEventListener('click', e => { if (e.target.matches('[data-action="save"]')) {...} })
参数解析别手写正则,优先用 URLPattern
从 #/user/123?tab=profile 提取 ID,写 pathname.match(/^\/user\/(\d+)$/) 会漏掉查询参数、斜杠结尾、URL 编码字符,且无法跨浏览器兼容。
- 现代浏览器(Chrome 110+、Edge 110+)直接用:
new URLPattern({ pathname: '/user/:id' }).exec(location.href)?.pathname.groups.id - 旧环境降级用
urlpattern-polyfill,比维护一堆正则更稳 - 提取后务必校验:
id && /^\d+$/.test(id),再转数字;别直接拼进 HTML,防 XSS,用textContent或模板引擎的安全渲染 - 避免模糊匹配:
location.hash.indexOf('/user')会误中/user-profile,必须精确路径匹配
服务端 fallback 是 pushState 模式的生死线
用 history.pushState 却没配服务端 fallback,等于给所有直链和刷新行为埋雷——用户分享链接、微信内打开、手动刷新,服务器直接返回 404,JS 根本没机会执行。
立即学习“前端免费学习笔记(深入)”;
- Nginx 配置关键行:
try_files $uri $uri/ /index.html; - Netlify 用
_redirects文件:/* /index.html 200 - Vercel 在
vercel.json中加:"rewrites": [{ "source": "(.*)", "destination": "/index.html" }] - hash 模式虽免配置,但 URL 带
#,SEO 友好度低,部分爬虫仍忽略;若真要 SEO,pushState + fallback 是唯一可行路径
实际项目里,最容易被忽略的是 DOM 节点膨胀和服务端 fallback 之间的耦合关系:一个没控制好,另一个再规范也救不回白屏或 404。路由逻辑写得再漂亮,节点数超 2000 或刷新崩掉,用户感知就是“卡”或“打不开”。



















