History对象
在chrome中控制台输入”history”查看对象:
{
length: 1
pushState: f(),
repalceState: f(),
scrollRestoration: "auto"
state: null
__proto__: History
}
History属性
(1)History.length (只读)
返回一个整数,该整数表示会话历史中元素的数目,包括当前加载的页。例如,在一个新的选项卡加载的一个页面中,这个属性返回1。
(2)History.state (只读)
返回一个表示历史堆栈顶部的状态的值。这是一种可以不必等待popstate 事件而查看状态而的方式。
(3)History.scrollRestoration
允许Web应用程序在历史导航上显式地设置默认滚动恢复行为。此属性可以是自动的(auto)或者手动的(manual)。
History方法
(1)History.back()
前往上一页, 用户可点击浏览器左上角的返回按钮模拟此方法. 等价于 history.go(-1)。
注意:当浏览器会话历史记录处于第一页时调用此方法没有效果,而且也不会报错。
(2)History.forward()
在浏览器历史记录里前往下一页,用户可点击浏览器左上角的前进按钮模拟此方法. 等价于 history.go(1).
注意:当浏览器历史栈处于最顶端时( 当前页面处于最后一页时 )调用此方法没有效果也不报错。
(3)History.go(n)
通过当前页面的相对位置从浏览器历史记录( 会话记录 )加载页面。比如:参数为-1的时候为上一页,参数为1的时候为下一页. 当整数参数超出界限时,例如: 如果当前页为第一页,前面已经没有页面了,我传参的值为-1,那么这个方法没有任何效果也不会报错。调用没有参数的 go() 方法或者不是整数的参数时也没有效果。( 这点与支持字符串作为url参数的IE有点不同)。传0会刷新当前页面。
(4)history.pushState(state, title , URL)
添加历史记录中的条目。不会立即加载页面的情况下改变了当前URL地址,往历史记录添加一条条目,除非刷新页面等操作。
三个参数:
- 状态对象
state是一个JavaScript对象,popstate事件的state属性包含该历史记录条目状态对象的副本。
状态对象可以是能被序列化的任何东西。原因在于Firefox将状态对象保存在用户的磁盘上,以便在用户重启浏览器时使用,我们规定了状态对象在序列化表示后有640k的大小限制。如果你给 pushState() 方法传了一个序列化后大于640k的状态对象,该方法会抛出异常。如果你需要更大的空间,建议使用 sessionStorage 以及 localStorage.
- 标题
Firefox 目前忽略这个参数,但未来可能会用到。在此处传一个空字符串应该可以安全的防范未来这个方法的更改。或者,你可以为跳转的state传递一个短标题。
- URL
新的历史URL记录。新URL不必须为绝对路径。如果新URL是相对路径,那么它将被作为相对于当前URL处理。新URL必须与当前URL同源,否则 pushState() 会抛出一个异常。该参数是可选的,缺省为当前URL。
注意: pushState() 绝对不会触发 hashchange 事件,即使新的URL与旧的URL仅哈希不同也是如此。
(5)history.replaceState(state, title , URL)
更改历史记录中的当前条目。不会立即加载页面的情况下改变了当前URL地址,并改变历史记录的当前条目,除非刷新页面等操作。
History相关事件
(1)popstate 事件
每当活动的历史记录项发生变化时, popstate 事件都会被传递给window对象。如果当前活动的历史记录项是被 pushState 创建的,或者是由 replaceState 改变的,那么 popstate 事件的状态属性 state 会包含一个当前历史记录状态对象的拷贝。
// 绑定事件处理函数.
window.onpopstate = function(event) {
alert("location: " + document.location + ", state: " + JSON.stringify(event.state));
};
// 添加并激活一个历史记录条目 http://example.com/example.html?page=1,条目索引为1
history.pushState({page: 1}, "title 1", "?page=1");
// 添加并激活一个历史记录条目 http://example.com/example.html?page=2,条目索引为2
history.pushState({page: 2}, "title 2", "?page=2");
// 修改当前激活的历史记录条目 http://ex..?page=2 变为 http://ex..?page=3,条目索引为3
history.replaceState({page: 3}, "title 3", "?page=3");
// 弹出 "location: http://example.com/example.html?page=1, state: {"page":1}"
history.back();
// 弹出 "location: http://example.com/example.html, state: null
history.back();
// 弹出 "location: http://example.com/example.html?page=3, state: {"page":3}
history.go(2);
注意:既然 history.pushState 和 history.replaceState 都不会触发页面的更新,我们就需要手动给 window 对象添加 pushState 和 replaceState 事件,这个很重要!
const listenWrapper = function (type) {
const _func = history[type];
return function () {
console.log(this);
const func = _func.apply(this, arguments);
const e = new Event(type);
e.arguments = arguments;
window.dispatchEvent(e);
return func;
};
};
history.pushState = listenWrapper('pushState');
history.replaceState = listenWrapper('replaceState');
window.addEventListener('pushState', function (e) {
console.log(e)
});
解释如下:
- 在pushState执行的时候创建自定义事件
- 在pushSatate外部写自定义事件的监听事件
- 在pushState执行的时候执行自定义事件
获取当前状态
页面加载时,或许会有个非null的状态对象。这是有可能发生的,举个例子,假如页面(通过pushState() 或 replaceState() 方法)设置了状态对象而后用户重启了浏览器。那么当页面重新加载时,页面会接收一个onload事件,但没有 popstate 事件。然而,假如你读取了history.state属性,你将会得到如同popstate 被触发时能得到的状态对象。
你可以读取当前历史记录项的状态对象state,而不必等待popstate 事件。
思路
.
Demo示例
监听点击事件禁止默认跳转操作,手动利用history实现一套跳转逻辑,根据location.pathname渲染界面。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta ="X-UA-Compatible" content="ie=edge"/>
<title>Document</title>
</head>
<body>
<ul>
<li>
<a href="/a">a</a>
</li>
<li>
<a href="/b">b</a>
</li>
<li>
<a href="/c">c</a>
</li>
</ul>
<div id="view"></div>
<script>
var view = null;
// 页面加载完不会触发 hashchange,这里主动触发一次 hashchange 事件,
// 该事件快于onLoad,所以需要在这里操作
window.addEventListener('DOMContentLoaded', function () {
view = document.querySelector('#view');
document
.querySelectorAll('a[href]')
.forEach(e => e.addEventListener('click', function (_e) {
_e.preventDefault();
history.pushState(null, '', e.getAttribute('href'));
viewChange();
}));
viewChange();
});
// 监听路由变化
window.addEventListener('popstate', viewChange);
// 渲染视图
function viewChange() {
switch (location.pathname) {
case '/b':
view.innerHTML = 'b';
break;
case '/c':
view.innerHTML = 'c';
break;
default:
view.innerHTML = 'a';
break;
}
}
</script>
</body>
</html>
————————————————
智一面|前端面试必备练习题