🟩 两种核心方案
1️⃣ Hash 模式(早期方案)
👉 URL 形式:
https://example.com/#/home
https://example.com/#/about
原理
#后面的部分叫做 hash,hash 变化不会触发浏览器向服务器发送请求,页面不会刷新- 浏览器只会触发
hashchange事件,浏览器只是滚动到对应锚点。 - hash 内容不会被包含在 HTTP 请求中,天然无需服务端配置
// 监听 hash 变化
window.addEventListener('hashchange', () => {
const path = location.hash.slice(1) // 去掉 #,得到 /about
renderPage(path)
})
// 跳转
location.hash = '/about' // 不刷新,触发 hashchange 事件
优点
- 兼容性极好(支持所有浏览器,包括老旧 IE)
- 开箱即用,实现成本极低
- 无需服务端配合,部署简单
缺点
- URL 不美观,带有
#符号 - 锚点功能被占用,无法用于页面内滚动
- 对 SEO(搜索引擎优化)不友好
2️⃣ History(历史) API(主流方案)
👉 URL 形式:
https://example.com/about
原理
- 基于 HTML5 新增的
historyAPI 实现 - URL 简洁美观,和传统后端路由格式一致
- 必须服务端配合,否则刷新页面会 404
// 新增一条历史记录,跳转路由(不刷新)
history.pushState(state, title, '/about')
// 替换当前历史记录,不新增记录
history.replaceState(state, title, '/home')
// 监听浏览器 前进/后退
window.addEventListener('popstate', () => {
renderPage(location.pathname)
})
关键补充:
pushState/replaceState只会修改浏览器地址栏和历史记录,不会发送网络请求、不会刷新页面popstate事件只会在浏览器前进后退时触发,调用pushState不会触发该事件
优点
- URL 干净优雅,无
# - 支持路由传参
state,数据不暴露在地址栏 - 对 SEO 更友好
缺点
- 依赖 HTML5,不支持极低版本浏览器
- 必须服务端配置,否则刷新 404
为什么 History 模式刷新会 404?
前端路由仅在浏览器端生效
刷新时,浏览器会向服务器请求 /about 这个真实路径
服务器没有这个文件 / 接口,直接返回 404
解决方案:服务端配置将所有请求重定向到 index.html,交给前端路由解析
🟩 React / Vue 是怎么做的
👉 本质就是封装了上面两种方式:
- React Router
- Vue Router
👉 内部:
- 监听 URL 变化
- 根据路径渲染组件