JavaScript利用history对象手写个 vue-router

什么是history对象

DOM window 对象通过 history 对象提供了对浏览器历史的访问。它暴露了很多有用的方法和属性,允许你在用户浏览历史中向前和向后跳转,同时——从HTML5开始——提供了对history栈中内容的操作。

譬如平时使用比较多的 ,向前和向后跳转

在history中向后跳转:

window.history.back();

这和用户点击浏览器回退按钮的效果相同。

类似地,你可以向前跳转(如同用户点击了前进按钮):

window.history.forward();

跳转到 history 中指定的一个点

你可以用 go() 方法载入到会话历史中的某一特定页面, 通过与当前页面相对位置来标志 (当前页面的相对位置标志为0).

向后移动一个页面 (等同于调用 back()):

window.history.go(-1);

向前移动一个页面, 等同于调用了 forward():

window.history.go(1);

类似地,你可以传递参数值2并向前移动2个页面,等等。

您可以通过查看长度属性的值来确定的历史堆栈中页面的数量:

var numberOfEntries = window.history.length;

注意: IE 支持传递URLs作为参数给 go(); 这在Gecko是不标准且不支持的。

而前面这些 History 属性, 要实现一个类似 vue-router的功能还是不够的, 在 html5, 新增的history.pushState和history.replaceState 刚好能满足我们的需求

两个api都接受三个参数

  • 状态对象(state object):一个JavaScript对象,与用pushState()方法创建的新历史记录条目关联。无论何时用户导航到新创建的状态,popstate事件都会被触发,并且事件对象的state属性都包含历史记录条目的状态对象的拷贝。
  • 标题(title):FireFox浏览器目前会忽略该参数,虽然以后可能会用上。考虑到未来可能会对该方法进行修改,传一个空字符串会比较安全。或者,你也可以传入一个简短的标题,标明将要进入的状态。
  • 地址(URL): 新的历史记录条目的地址。浏览器不会在调用pushState()方法后加载该地址,但之后,可能会试图加载,例如用户重启浏览器。新的URL不一定是绝对路径;如果是相对路径,它将以当前URL为基准;传入的URL与当前URL应该是同源的,否则,pushState()会抛出异常。该参数是可选的;不指定的话则为文档当前URL。

相同之处是两个API都会操作浏览器的历史记录,而不会引起页面的刷新。不同之处在于pushState会增加一条新的历史记录,而replaceState则会替换当前的历史记录

大家可以先在控制台试试,看看地址栏发生了什么变化

window.history.pushState(null, null, "test");
window.history.pushState(null, null, "/test");
window.history.pushState(null, null, "#/hello");
window.history.pushState(null, null, "?name=");

实现代码

<!DOCTYPE html>

<html lang="en">
<head>
<meta charset="UTF-8">
<title>前端路由实现</title>
<style>
.wapper {
width: 500px;
height: 500px;
border: 1px solid #999999;
margin: 0 auto;
}

.wapper ul {
height: 39px;
border-bottom: 1px solid #999999;
}

.wapper ul li {
padding-left: 12px;
display: inline-block;
list-style: none;
}

.content {
padding: 30px;
}

a {
cursor: pointer;
}
</style>
</head>
<body>
<section class="wapper">
<ul class="header">
<li><a href="javascript:void(0)">首页</a></li>
<li><a href="javascript:void(0)">新闻</a></li>
<li><a href="javascript:void(0)">关于</a></li>
</ul>
<div class="content">
<!-- 内容加载区域 -->
</div>
</section>
<script>
let header = document.querySelector('.header')
let content = document.querySelector('.content')
// 页面初始化
let url = '默认展示内容';
history.replaceState(url, null, '');
content.innerHTML = url
// 点击事件处理
header.removeEventListener('click', _eventCallBackFun)
header.addEventListener('click', _eventCallBackFun)
function _eventCallBackFun(e) {
if (e.target.tagName === 'A')
url = e.target.innerHTML
content.innerHTML = url
history.pushState(url, null, '#/' + url);
}
// 监听 popstate 事件
window.addEventListener('popstate', e => {
url = e.state
content.innerHTML = url
})
</script>
</body>
</html>
分享到