Skip to main content

前端路由

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 效果较差