前端实现路由的两种方式浏览器页面跳转是通过后台实现的,自从前后端分离,前端也把路由跳转给接管了,就是说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 地址美观,便于理解 需要后台或者服务器配合刷新跳转