两种前端路由的实现方式

两种前端路由的实现方式

前后端分离开发模式,后端会把路由控制丢在前端,这几天再开发单页面小的项目,手动撸了个路由。前端路由实现有两种方法。

1. history.pushState/ history.replaceState / window.popstate

HTML5 History API包括2个方法:history.pushState()和history.replaceState(),和1个事件:window.onpopstate。

pushState

history.pushState(stateObject, title, url),包括三个参数。

  • stateObject 存储该url对应的状态对象,该对象可在onpopstate事件中获取,也可在history对象中获取
  • title 目前浏览器未实现,为nul
  • 路径url,般设置为相对路径,如果设置为绝对路径时需要保证同源

pushState函数向浏览器的历史堆栈压入一个url为设定值的记录,并改变历史堆栈的当前指针至栈顶。

replaceState

该接口与pushState参数相同,含义也相同。唯一的区别在于replaceState是替换浏览器历史堆栈的当前历史记录为设定的url。需要注意的是,replaceState不会改动浏览器历史堆栈的当前指针。

onpopstate

该事件是window的属性。该事件会在调用浏览器的前进、后退以及执行history.forward、history.back、和history.go触发,因为这些操作有一个共性,即修改了历史堆栈的当前指针。在不改变document的前提下,一旦当前指针改变则会触发
下面是简易版本的实现方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<a data-href="/post"></a>
<a data-href="/login"></a>
const Router = [];
const addRoute = (path = '', handle = () => {}) => {
let obj = {
path,
handle
}
Router.push(obj);
}
//添加路由定义
addRoute('/post', function() {
//do something
});
addRoute('/login', function() {
//do something
})
//路由处理
const routeHandle = (path) => {
Router.forEach((item, index) => {
if(item.path === path) {
item.handle.apply(null, [path]);
return true;
}
})
return false;
}
//拦截默认的a标签行为
document.addEventListener('click', function(e) {
let dataset = e.target.dataset;
if(dataset) {
if(routeHandle(dataset.href)) {
//阻止默认行为
e.preventDefault();
}
}
});

2.hash + location.onhashchange

实现原理是通过监听hash变化,触发onhashchange事件回调。hash的变化会导致历史记录栈的变化,从而实现路由。

一个简易版的router实现源码,功能如下

  • 切换页面
  • 异步加载js
  • 异步传参