Codog

关注微信公众号:Codog代码狗

0%

前端路由实现原理:hash与history模式

网站最开始都是多页的,每个页面都对应一个完整结构的HTML文件,这样每次操作都会重新请求数据,造成资源浪费。

Ajax技术兴起,慢慢出现了SPA(单页应用),整个应用都在一个HTML文件上,大大减少数据请求,交互体验也变得更加流畅。

单页也有它的弊端,无法保留用户状态,页面刷新又恢复初始状态。这时就需要前端路由了。

实现方式主要有两种:

  • hash

hash的改变不会使页面刷新,浏览器也可以正常的前进后退,页面可以监听hashchange事件来响应变化,

1
2
3
window.addEventListener('hashchange', function(e) {
console.log(e.newURL, e.oldURL)
})

window.location.hash可以获取当前页面的hash

  • history模式

除了常用的history.back()history.forward(),HTML5为history增加了pushState, replaceState方法和state属性。

history.pushState() 和 history.replaceState() 均接收三个参数(state, title, url)
参数说明如下:

state:合法的 Javascript 对象,可以用在 popstate 事件中
title:现在大多浏览器忽略这个参数,可以直接用 null 代替
url:任意有效的 URL,用于更新浏览器的地址栏

pushState和replaceState都可以做到改变url的同时不刷新页面,并保留历史记录。

需要注意的是,history方式会直接修改url,所以url修改后页面刷新会出现404的情况,这时需要服务端增加配置,默认返回此单页应用的html数据

popstate事件:

每当活动的历史记录项发生变化时, popstate 事件都会被传递给window对象。如果当前活动的历史记录项是被 pushState 创建的,或者是由 replaceState 改变的,那么 popstate 事件的状态属性 state 会包含一个当前历史记录状态对象的拷贝。

调用history.pushState()或者history.replaceState()不会触发popstate事件. popstate事件只会在浏览器某些行为下触发, 比如点击后退、前进按钮(或者在JavaScript中调用history.back()、history.forward()、history.go()方法).

需要注意,只要历史记录发生变化就会触发,意味着无论hash还是history方式都会触发此事件。

页面加载时,或许会有个非null的状态对象。这是有可能发生的,举个例子,假如页面(通过pushState() 或 replaceState() 方法)设置了状态对象而后用户重启了浏览器。那么当页面重新加载时,页面会接收一个onload事件,但没有 popstate 事件。然而,假如你读取了history.state属性,你将会得到如同popstate 被触发时能得到的状态对象。

参考链接:

https://developer.mozilla.org/zh-CN/docs/Web/API/History_API

https://juejin.im/post/5d2d19ccf265da1b7f29b05f