Html5使用history對象history.pushState()和history.replaceState()方法添加和修改瀏覽歷史記錄

瀏覽器窗口有一個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';

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市晶默,隨后出現(xiàn)的幾起案子谨娜,更是在濱河造成了極大的恐慌,老刑警劉巖磺陡,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件趴梢,死亡現(xiàn)場離奇詭異,居然都是意外死亡币他,警方通過查閱死者的電腦和手機坞靶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蝴悉,“玉大人滩愁,你說我怎么就攤上這事”璺猓” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵廉丽,是天一觀的道長倦微。 經(jīng)常有香客問我,道長正压,這世上最難降的妖魔是什么欣福? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮焦履,結(jié)果婚禮上拓劝,老公的妹妹穿的比我還像新娘。我一直安慰自己嘉裤,他們只是感情好郑临,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著屑宠,像睡著了一般厢洞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上典奉,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天躺翻,我揣著相機與錄音,去河邊找鬼卫玖。 笑死公你,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的假瞬。 我是一名探鬼主播陕靠,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼迂尝,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了懦傍?” 一聲冷哼從身側(cè)響起雹舀,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎粗俱,沒想到半個月后说榆,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡寸认,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年签财,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片偏塞。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡唱蒸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出灸叼,到底是詐尸還是另有隱情神汹,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布古今,位于F島的核電站屁魏,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏捉腥。R本人自食惡果不足惜氓拼,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望抵碟。 院中可真熱鬧桃漾,春花似錦、人聲如沸拟逮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽敦迄。三九已至宪摧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間颅崩,已是汗流浹背几于。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留沿后,地道東北人沿彭。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像尖滚,于是被迫代替她去往敵國和親喉刘。 傳聞我的和親對象是個殘疾皇子瞧柔,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容