H5 History API pushState和replaceState方法
HTML5 history API
HTML5引入了history.pushState()和history.replaceState()方法。他们分别可以添加和修改历史记录的条目。
pushState()
history.replaceState(stateObj, title, [url])
-
stateObj:一个JavaScript对象,可以是任何可以序列化的对象。它与创建的新历史记录条目相关联。每当用户导航到新状态时,都会触发popstate事件(下面会讲)。
-
title:简短的标题(大部分浏览器都忽略了该参数)。
-
url:历史记录条目的URL。
浏览器为每个页面维护一个History栈。当执行pushState()指针所在的位置在栈顶时,会保留当前历史记录并添加一条新的历史记录条目并压入栈顶,同时修改指针指向新记录,History栈大小会增加。
当执行pushState()指针所在的位置不在栈顶在栈中间时,会将指针上面的记录移除并添加一条新的记录并压入栈顶。
当执行back(返回上一页)操作时,指针会移动到之前的一条记录,但是栈不会发生变化。
测试demo:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<button id="btn1">pushState</button>
<button id="btn2">getLen</button>
<span></span>
</body>
<script src="./js/jquery.min.js"></script>
<script>
$(document).ready(function() {
let i = 1;
$('span').html('当前历史记录栈中的总条目数:' + history.length);
$('#btn1').on('click', () => {
history.pushState({}, '', 'test' + i + '.html');
i++;
});
$('#btn2').on('click', () => {
$('span').html('当前历史记录栈中的总条目数:' + history.length);
});
});
</script>
</html>
replaceState()
history.replaceState(stateObj, title, [url])
replaceState()会将当前记录修改成指定的URL,但不会改变指针。
测试demo:
<body>
<button id="btn1">pushState</button>
<button id="btn2">replaceState</button>
<button id="btn3">getLen</button>
<span></span>
</body>
<script src="./js/jquery.min.js"></script>
<script>
$(document).ready(() => {
let i = 1;
$('span').html('当前历史记录栈中的总条目数:' + history.length);
$('#btn1').on('click', () => {
history.pushState({}, '', 'test' + i + '.html');
i++;
});
$('#btn2').on('click', () => {
history.replaceState({}, '', 'test' + i + '.html');
i++;
});
$('#btn3').on('click', () => {
$('span').html('当前历史记录栈中的总条目数:' + history.length);
});
});
</script>
popstate事件
popstate也是H5 History API 新增的一个接口,主要用于控制历史记录条目。
当历史记录条目更改时,将触发popstate事件。当用户在浏览器点击进行后退、前进,或者在js中调用histroy.back(),history.go(),history.forward()等,会触发popstate事件。但history.pushState()、history.replaceState()不会触发这个事件。
测试demo:
<body>
<button id="btn1">pushState</button>
<button id="btn2">replaceState</button>
<button id="btn3">forward</button>
<button id="btn4">back</button>
<span></span>
</body>
<script src="./js/jquery.min.js"></script>
<script>
$(document).ready(() => {
let i = 1;
$('#btn1').on('click', () => {
history.pushState({page: i}, '', 'test' + i + '.html');
i++;
});
$('#btn2').on('click', () => {
history.replaceState({page: i}, '', 'test' + i + '.html');
i++;
});
$('#btn3').on('click', () => {
history.forward();
});
$('#btn4').on('click', () => {
history.back();
});
window.addEventListener('popstate', (event) => {
console.log("state: " + JSON.stringify(event.state));
});
});
</script>
vue-router History 模式
前端路由最主要的特点就是通过改变URL,在不请求页面的情况下,更新页面视图。HTML5 history API 新增的两个方法就为此提供了方便。
vue-router 默认hash模式,使用URL的hash来模拟一个完整URL。hash为符号#
及后面的字符,如URLhttp://localhost:8080/#/Home
,hash就是#/Home
。hash不会包括在http请求中,所以修改hash内容不会重新请求页面。
history模式下则通过使用history.pushState API
来完成URL跳转而无须重新加载页面。通过上面的demo我们可以看到,使用history.pushState()和history.replaceState()无论URL怎么改变页面都只是修改了视图,但是不会发送新的请求。一旦我们刷新一下页面就会发现404资源文件不存在,不存在指定的html文件。