前端实现路由的两种方式浏览器页面跳转是通过后台实现的,自从前后端分离,前端也把路由跳转给接管了,就是说 url 的改变不发送给服务器,而是让浏览器自己处理,这样有一个好处可以减轻服务器的压力,一般适用于 SPA。
目前实现前端路由有两种方式,一种是 hash,一种是用 history api
hash 路由
hash 路由实现的原理是通过监听 window 的hashchange
事件,来做响应更新页面处理
hash 即 URL 中"#"字符后面的部分,有以下特点
- hash 值不会随着请求发送给服务器
- hash 改变不会导致重新加载页面
监听 hash 值改变
window.addEventListener( 'hashchange', () => { // ...路由跳转 }, false);
hash 的读写
可以通过location.hash
来读写 hash 值
hash 路由优缺点
优点:兼容低版本浏览器
缺点:不美观,会和锚点冲突
history api
hash 路由虽然可以满足前端路由跳转,但是不太美观,history api 可以解决这个问题,让 url 看起来跟原来服务器直接跳转方式没什么区别
- length:history 栈中的记录数
- back():返回上一页
- forward():前进下一页
- go(number|url):参数为负数返回,正数前进,**history.go(1) 相当于 history.forward() **
html5 提供两个新的方法pushState()
和replaceState()
以及一个全局监听事件popstate
pushState
history.pushState(state, title, url)
在 history 栈添加新记录
使用 pushState()可以改变 referrer,在用户发送 XMLHttpRequest 请求时会在 HTTP 头部的 referrer 会响应的改变,因为 referrer 是标识创建 XMLHttpRequest 对象时 this 所代表的 window 对象中 document 的 URL
假设在http://localhost:8080/index.html
中执行了以下代码:
var state = { id: 123 };history.pushState(state, null, 'a.html');
地址会变成http://localhost:8080/a.html
,但是页面不会加载 a.html
replaceState
replaceState(state, title, url)
是在 history 栈替换当前的记录,参数和效果与 pushState 类似
popstate 事件
每当处于激活状态的 history 栈发生变化时,popstate 事件就会在对应 window 对象上触发,但是注意的是 pushState 和 replaceState 不会触发 popstate 事件
popstate 事件只会在浏览器某些行为下触发, 比如浏览器后退、前进按钮,js 代码里的 history.back(),history.go(),history.forward(),location.hash
history.pushState({ id: 1 }, null, '?page=1');history.pushState({ id: 2 }, null, '?page=2');history.replaceState({ id: 3 }, null, '?page=3');history.back();
此时的 url 是 http://localhost:8080/a.html,触发了 popstate 事件,event 对象的 state 值为{id: 1}
history.state
页面加载时,或许会有个非 null 的状态对象。这是有可能发生的,举个例子,假如页面(通过 pushState()或 replaceState()方法)设置了状态对象而后用户重启了浏览器。那么当页面重新加载时,页面会接收一个 onload 事件,但没有 popstate 事件。然而,假如你读取了 history.state 属性,你将会得到如同 popstate 被触发时能得到的状态对象。
兼容低版本浏览器history api库,提供了跟 history 一样接口写法
hash 和 history 的区别
模式 | 优点 | 缺点 |
---|---|---|
hash | 使用简单、无需后台支持 | 1. 不美观,与锚点冲突 2. 在 url 中以 hash 形式存在,不会传到后台 |
history | 地址美观,便于理解 | 需要后台或者服务器配合刷新跳转 |