单页应用(SPA)的前端路由实现原理

前端router的实现通常有2种方式:
1. window.history
2. location.hash

history

history的几个常用方法:
* history.back(): 等同于点击浏览器的后退按钮
* history.forward(): 等同于点击浏览器的前进按钮
* history.go(n): go(1)等同于forward(), go(-1)等同于back(), go(0)等同于刷新当前页面
如果移动的位置超出了访问历史的边界,以上三个方法并不报错,而是静默失败。

HTML5中, history对象提出了 pushState()方法和 replaceState()方法,
这两个方法可以用来向历史栈中添加数据,就好像 url变化了一样(过去只有 url 变化历史栈才会变化),
这样就可以很好的模拟浏览历史和前进后退了,现在的前端路由也是基于这个原理实现的。

history.pushState && history.replaceState

pushState(stateObj, title, url) 方法向历史栈中写入数据,
其第一个参数是要写入的数据对象(不大于640kB),第二个参数是页面的 title, 第三个参数是 url (相对路径)。

  • stateObj: 一个与指定网址相关的状态对象,popstate事件触发时,该对象会传入回调函数。如果不需要这个对象,此处可以填null。
  • title: 新页面的标题,但是所有浏览器目前都忽略这个值,因此这里可以填null。
  • url: 新的网址,必须与当前页面处在同一个域。浏览器的地址栏将显示这个网址。(若url违背同源策略时将会报错)

pushState方法不会触发页面刷新,只是导致history对象发生变化,地址栏会有反应,只有当触发前进后退等事件(back()和forward()等)时浏览器才会刷新。

replaceState(stateObj, title, url)pushState的区别,就在于它不是写入而是替换修改浏览历史中当前纪录,其余和 pushState一模一样。

popstate事件

定义:每当同一个文档的浏览历史(即history对象)出现变化时,就会触发popstate事件。

注意:
仅仅调用pushState方法或replaceState方法 ,并不会触发该事件,只有用户点击浏览器倒退按钮和前进按钮,或者使用JavaScript调用back、forward、go方法时才会触发。
另外,该事件只针对同一个文档,如果浏览历史的切换,导致加载不同的文档,该事件也不会触发。

可以为popstate事件指定回调函数。这个回调函数的参数是一个event事件对象,event对象的state属性指向pushState和replaceState方法为当前URL所提供的状态对象(即这两个方法的第一个参数)。

前端路由的代码实现

hash

window 对象中有一个事件是 onhashchange,有以下几种情况触发条件:

  • 直接更改浏览器地址,在最后面增加或改变#hash;
  • 通过改变location.href或location.hash的值;
  • 通过触发点击带锚点的链接;
  • 浏览器前进后退可能导致hash的变化,前提是两个网页地址中的hash值不同。