瀏覽器窗口有一個history對象檐春,用來保存瀏覽歷史况芒。
如果當前窗口先后訪問了三個網(wǎng)址唠椭,那么history對象就包括三項跳纳,history.length屬性等于3。
history.length // 3
history對象提供了一系列方法贪嫂,允許在瀏覽歷史之間移動寺庄。
back():移動到上一個訪問頁面,等同于瀏覽器的后退鍵。
forward():移動到下一個訪問頁面斗塘,等同于瀏覽器的前進鍵赢织。
go():接受一個整數(shù)作為參數(shù),移動到該整數(shù)指定的頁面馍盟,比如go(1)相當于forward()于置,go(-1)相當于back()。
history.back();
history.forward();
history.go(-2);
如果移動的位置超出了訪問歷史的邊界贞岭,以上三個方法并不報錯八毯,而是默默的失敗。
history.go(0)相當于刷新當前頁面瞄桨。
history.go(0);
常見的“返回上一頁”鏈接话速,代碼如下。
document.getElementById('backLink').onclick = function () {
? window.history.back();
}
注意芯侥,返回上一頁時泊交,頁面通常是從瀏覽器緩存之中加載,而不是重新要求服務器發(fā)送新的網(wǎng)頁筹麸。
history.pushState()
HTML5為history對象添加了兩個新方法活合,history.pushState()和history.replaceState(),用來在瀏覽歷史中添加和修改記錄物赶。
if (!!(window.history && history.pushState)){
? // 支持History API
} else {
? // 不支持
}
上面代碼可以用來檢查白指,當前瀏覽器是否支持History API。如果不支持的話酵紫,可以考慮使用Polyfill庫History.js告嘲。
history.pushState方法接受三個參數(shù),依次為:
state:一個與指定網(wǎng)址相關(guān)的狀態(tài)對象奖地,popstate事件觸發(fā)時橄唬,該對象會傳入回調(diào)函數(shù)。如果不需要這個對象参歹,此處可以填null仰楚。
title:新頁面的標題,但是所有瀏覽器目前都忽略這個值犬庇,因此這里可以填null僧界。
url:新的網(wǎng)址,必須與當前頁面處在同一個域臭挽。瀏覽器的地址欄將顯示這個網(wǎng)址捂襟。
假定當前網(wǎng)址是example.com/1.html,我們使用pushState方法在瀏覽記錄(history對象)中添加一個新記錄欢峰。
var stateObj = { foo: 'bar' };
history.pushState(stateObj, 'page 2', '2.html');
添加上面這個新記錄后葬荷,瀏覽器地址欄立刻顯示example.com/2.html涨共,但并不會跳轉(zhuǎn)到2.html,甚至也不會檢查2.html是否存在宠漩,它只是成為瀏覽歷史中的最新記錄举反。假定這時你訪問了google.com,然后點擊了倒退按鈕扒吁,頁面的url將顯示2.html照筑,但是內(nèi)容還是原來的1.html。你再點擊一次倒退按鈕瘦陈,url將顯示1.html,內(nèi)容不變波俄。
總之晨逝,pushState方法不會觸發(fā)頁面刷新,只是導致history對象發(fā)生變化懦铺,地址欄會有反應捉貌。
如果pushState的url參數(shù),設置了一個新的錨點值(即hash)冬念,并不會觸發(fā)hashchange事件趁窃。如果設置了一個跨域網(wǎng)址,則會報錯急前。
// 報錯
history.pushState(null, null, 'https://twitter.com/hello');
上面代碼中醒陆,pushState想要插入一個跨域的網(wǎng)址,導致報錯裆针。這樣設計的目的是刨摩,防止惡意代碼讓用戶以為他們是在另一個網(wǎng)站上。
history.replaceState()
history.replaceState方法的參數(shù)與pushState方法一模一樣世吨,區(qū)別是它修改瀏覽歷史中當前紀錄澡刹。
假定當前網(wǎng)頁是example.com/example.html。
history.pushState({page: 1}, 'title 1', '?page=1');
history.pushState({page: 2}, 'title 2', '?page=2');
history.replaceState({page: 3}, 'title 3', '?page=3');
history.back()
// url顯示為http://example.com/example.html?page=1
history.back()
// url顯示為http://example.com/example.html
history.go(2)
// url顯示為http://example.com/example.html?page=3
history.state屬性
history.state屬性返回當前頁面的state對象耘婚。
history.pushState({page: 1}, 'title 1', '?page=1');
history.state
// { page: 1 }
popstate事件
每當同一個文檔的瀏覽歷史(即history對象)出現(xiàn)變化時罢浇,就會觸發(fā)popstate事件。
需要注意的是沐祷,僅僅調(diào)用pushState方法或replaceState方法 嚷闭,并不會觸發(fā)該事件,只有用戶點擊瀏覽器倒退按鈕和前進按鈕戈轿,或者使用JavaScript調(diào)用back凌受、forward、go方法時才會觸發(fā)思杯。另外胜蛉,該事件只針對同一個文檔挠进,如果瀏覽歷史的切換,導致加載不同的文檔誊册,該事件也不會觸發(fā)领突。
使用的時候,可以為popstate事件指定回調(diào)函數(shù)案怯。這個回調(diào)函數(shù)的參數(shù)是一個event事件對象君旦,它的state屬性指向pushState和replaceState方法為當前URL所提供的狀態(tài)對象(即這兩個方法的第一個參數(shù))。
window.onpopstate = function (event) {
? console.log('location: ' + document.location);
? console.log('state: ' + JSON.stringify(event.state));
};
// 或者
window.addEventListener('popstate', function(event) {
? console.log('location: ' + document.location);
? console.log('state: ' + JSON.stringify(event.state));
});
上面代碼中的event.state嘲碱,就是通過pushState和replaceState方法金砍,為當前URL綁定的state對象。
這個state對象也可以直接通過history對象讀取麦锯。
var currentState = history.state;
注意恕稠,頁面第一次加載的時候,在load事件發(fā)生后扶欣,Chrome和Safari瀏覽器(Webkit核心)會觸發(fā)popstate事件鹅巍,而Firefox和IE瀏覽器不會。
URLSearchParams API
URLSearchParams API用于處理URL之中的查詢字符串料祠,即問號之后的部分骆捧。沒有部署這個API的瀏覽器,可以用url-search-params這個墊片庫髓绽。
var paramsString = 'q=URLUtils.searchParams&topic=api';
var searchParams = new URLSearchParams(paramsString);
URLSearchParams有以下方法敛苇,用來操作某個參數(shù)。
has():返回一個布爾值梧宫,表示是否具有某個參數(shù)
get():返回指定參數(shù)的第一個值
getAll():返回一個數(shù)組接谨,成員是指定參數(shù)的所有值
set():設置指定參數(shù)
delete():刪除指定參數(shù)
append():在查詢字符串之中,追加一個鍵值對
toString():返回整個查詢字符串
var paramsString = 'q=URLUtils.searchParams&topic=api';
var searchParams = new URLSearchParams(paramsString);
searchParams.has('topic') // true
searchParams.get('topic') // "api"
searchParams.getAll('topic') // ["api"]
searchParams.get('foo') // null塘匣,注意Firefox返回空字符串
searchParams.set('foo', 2);
searchParams.get('foo') // 2
searchParams.append('topic', 'webdev');
searchParams.toString() // "q=URLUtils.searchParams&topic=api&foo=2&topic=webdev"
searchParams.append('foo', 3);
searchParams.getAll('foo') // [2, 3]
searchParams.delete('topic');
searchParams.toString() // "q=URLUtils.searchParams&foo=2&foo=3"
URLSearchParams還有三個方法脓豪,用來遍歷所有參數(shù)。
keys():遍歷所有參數(shù)名
values():遍歷所有參數(shù)值
entries():遍歷所有參數(shù)的鍵值對
上面三個方法返回的都是Iterator對象忌卤。
var searchParams = new URLSearchParams('key1=value1&key2=value2');
for (var key of searchParams.keys()) {
? console.log(key);
}
// key1
// key2
for (var value of searchParams.values()) {
? console.log(value);
}
// value1
// value2
for (var pair of searchParams.entries()) {
? console.log(pair[0]+ ', '+ pair[1]);
}
// key1, value1
// key2, value2
在Chrome瀏覽器之中扫夜,URLSearchParams實例本身就是Iterator對象,與entries方法返回值相同驰徊。所以笤闯,可以寫成下面的樣子。
for (var p of searchParams) {
? console.log(p);
}
下面是一個替換當前URL的例子棍厂。
// URL: https://example.com?version=1.0
var params = new URLSearchParams(location.search.slice(1));
params.set('version', 2.0);
window.history.replaceState({}, '', `${location.pathname}?${params}`);
// URL: https://example.com?version=2.0
URLSearchParams實例可以當作POST數(shù)據(jù)發(fā)送颗味,所有數(shù)據(jù)都會URL編碼。
let params = new URLSearchParams();
params.append('api_key', '1234567890');
fetch('https://example.com/api', {
? method: 'POST',
? body: params
}).then(...)
DOM的a元素節(jié)點的searchParams屬性牺弹,就是一個URLSearchParams實例浦马。
var a = document.createElement('a');
a.) // "api"
URLSearchParams還可以與URL接口結(jié)合使用时呀。
var url = new URL(location);
var foo = url.searchParams.get('foo') || 'somedefault';