前端路由
1. 路由是什么
URL 到对应处理程序的映射
web 路由可以由服务端或前端实现,根据实现方式分为Hash 路由 和 History 路由
前端路由 相对于 服务端路由,可以在页面无刷新的情况下进行页面切换,故产生了无刷新的单页应用开发模式 SPA
2. Hash 路由
在 URI 的组成中, fragment 是 Hash 路由所读取的内容
fragment 本质是用来标识次级资源,具有以下特点
- 修改 fragment 内容不会触发网页重载
- 修改 fragment 内容会改变浏览器历史记录
- 修改 fragment 内容会触发浏览器 onhashchange 事件
2.1 实现原理
可以监听 hashchange 事件监听页面 hash 变化,解析 hash 值来切换页面
/** * 解析 hash */const parseHash = hash => { // 去除 # 号 hash = hash.replace(/^#/, "")
const parsed = hash.split("?")
// 返回 hash path 和 query return { pathname: parsed[0], search: parsed[1] }}
const onHashChange = () => { const {pathname, search} = parseHash(location.hash)
// 切换页面内容 switch(pathname) { case "/home": document.body.innerHTML = `olu cool` return default: return }}
window.addEventListener("hashchange", onHashChange)2.2 优点
- 兼容性好
- 无需服务端配置
2.3 缺点
- 服务端无法获取 hash 部分内容
- 可能会和锚点功能冲突
- SEO 不友好
3. History 路由
通过浏览器原生提供的操作 History 的能力实现路由功能
3.1 实现原理
依赖 History API 中的 pushState 方法 和 replaceState 方法 以及 popstate 事件
- history.pushState:将给定的 Data 添加到当前标签页的历史记录栈中
- history.replaceState:将给定的 Data 更新到历史记录栈中最新的一条记录中
- popstate: 监听历史记录的变化
const onHistoryChange = () => { const {pathname, search} = location
// 根据不同页面执行不同内容 switch (pathname) { case '/home': document.body.innerHTML = `olu cool, ${search.replace(/^\?/, "")}` return default: document.body.innerHTML = 'olu cute' return }}
// 页面跳转const pushState = (target) => { history.pushState(null, '', target) onHistoryChange()}
// xx 秒后路由跳转setTimeout(() => { pushState("/home?name=oluCool")}, 2000)
setTimeout(() => { history.back()}, 6000)
window.addEventListener("popstate", onHistoryChange)3.2 优点
- 服务端可以获取到完整的链接和参数
- 前端监控友好
- SEO 相对 Hash 友好
3.3 缺点
- 兼容性稍弱
- 需要服务端额外配置(各 path 均指向同一个 HTML)
4. 前端路由的优缺点
4.1 优点
- 无刷新切换内容,体验更好
- 减轻服务端压力
4.2 缺点
- 初次加载耗时长
- SEO 效果较差