摘要:而唯一不引發(fā)刷新的參數(shù)并不會(huì)發(fā)送到服務(wù)器,因此服務(wù)器無(wú)法獲得狀態(tài)。目前建議設(shè)置為空字符串。此外請(qǐng)注意,及本身調(diào)用時(shí)是不觸發(fā)事件的。我認(rèn)為,按照漸進(jìn)增強(qiáng)的思路,這樣就是最好的了,也就是只使用較少的代碼優(yōu)化高級(jí)瀏覽器的使用體驗(yàn)。
HTML5 history API有什么用呢?
從Ajax翻頁(yè)的問(wèn)題說(shuō)起請(qǐng)想象你正在看一個(gè)視頻下面的評(píng)論,在翻到十幾頁(yè)的時(shí)候,你發(fā)現(xiàn)一個(gè)寫(xiě)得稍長(zhǎng),但非常有趣的評(píng)論。正當(dāng)你想要停下滾輪細(xì)看的時(shí)候,手殘按到了F5。然后,頁(yè)面刷新了,評(píng)論又回到了第一頁(yè),所以你又要重新翻一次。
再或者,你想把這個(gè)評(píng)論發(fā)給別人分享,一面給了別人頁(yè)面地址(為什么不直接復(fù)制呢?因?yàn)橐B帶視頻等場(chǎng)景啊),一面又要加一句囑咐:請(qǐng)翻到下面評(píng)論的第XX頁(yè)的XX樓。
這就是問(wèn)題。試想一下,如果瀏覽器能記住你當(dāng)前的狀態(tài)(比如看到了第十幾頁(yè)),而不是一刷新就還原,是不是就顯得智能多了?
為什么用Ajax?用Ajax實(shí)現(xiàn)翻頁(yè)等內(nèi)容切換是有原因的。在傳統(tǒng)的無(wú)Ajax的站點(diǎn)里,頁(yè)面A和頁(yè)面B可能只有10%的地方是不同的,其他90%的內(nèi)容(尤其是導(dǎo)航、頁(yè)腳等公用元素)都是一樣的,但卻仍然需要瀏覽器下載并顯示新的一整個(gè)頁(yè)面。而如果使用Ajax,不僅節(jié)省了瀏覽器需要下載的資源,而且無(wú)刷新切換明顯比頁(yè)面跳轉(zhuǎn)更平滑、流暢。
就視頻下面的評(píng)論來(lái)說(shuō),Ajax可以說(shuō)是必須的。視頻這樣的重量級(jí)元素,動(dòng)不動(dòng)給你重新加載一次,不能忍。
傳統(tǒng)的跳轉(zhuǎn)翻頁(yè)的可取之處傳統(tǒng)的不使用Ajax的站點(diǎn),每一個(gè)翻頁(yè)是一個(gè)跳轉(zhuǎn),然后你可以在瀏覽器地址欄里看到諸如?page=2這樣的參數(shù)。每一頁(yè)就這樣通過(guò)地址欄的URL做了標(biāo)記,每一次請(qǐng)求,瀏覽器都會(huì)根據(jù)參數(shù)返回正確的頁(yè)碼。
所以,傳統(tǒng)的跳轉(zhuǎn)翻頁(yè),刷新也不會(huì)丟失狀態(tài)。
結(jié)合兩者現(xiàn)在我們就可以想到,如果在Ajax更新頁(yè)面局部?jī)?nèi)容的同時(shí),也在地址欄的URL里更新?tīng)顟B(tài)參數(shù),就可以做出更完美的Ajax翻頁(yè)了。
不過(guò),JavaScript修改location的除hash外的任意屬性,頁(yè)面都會(huì)以新URL重新加載。而唯一不引發(fā)刷新的hash參數(shù)并不會(huì)發(fā)送到服務(wù)器,因此服務(wù)器無(wú)法獲得狀態(tài)。
然后,HTML5 history API將解決這個(gè)問(wèn)題。
介紹HTML5 history APIHTML5 history API只包括2個(gè)方法:history.pushState()和history.replaceState(),以及1個(gè)事件:window.onpopstate。
history.pushState()它的完全體是 history.pushState(stateObject, title, url),包括三個(gè)參數(shù)。
第1個(gè)參數(shù)是狀態(tài)對(duì)象,它可以理解為一個(gè)拿來(lái)存儲(chǔ)自定義數(shù)據(jù)的元素。它和同時(shí)作為參數(shù)的url會(huì)關(guān)聯(lián)在一起。
第2個(gè)參數(shù)是標(biāo)題,是一個(gè)字符串,目前各類(lèi)瀏覽器都會(huì)忽略它(以后才有可能啟用,用作頁(yè)面標(biāo)題),所以設(shè)置成什么都沒(méi)關(guān)系。目前建議設(shè)置為空字符串。
第3個(gè)參數(shù)是URL地址,一般會(huì)是簡(jiǎn)單的?page=2這樣的參數(shù)風(fēng)格的相對(duì)路徑,它會(huì)自動(dòng)以當(dāng)前URL為基準(zhǔn)。需要注意的是,本參數(shù)URL需要和當(dāng)前頁(yè)面URL同源,否則會(huì)拋出錯(cuò)誤。
調(diào)用pushState()方法將新生成一條歷史記錄,方便用瀏覽器的“后退”和“前進(jìn)”來(lái)導(dǎo)航(“后退”可是相當(dāng)常用的按鈕)。另外,從URL的同源策略可以看出,HTML5 history API的出發(fā)點(diǎn)是很明確的,就是讓無(wú)跳轉(zhuǎn)的單站點(diǎn)也可以將它的各個(gè)狀態(tài)保存為瀏覽器的多條歷史記錄。當(dāng)通過(guò)歷史記錄重新加載站點(diǎn)時(shí),站點(diǎn)可以直接加載到對(duì)應(yīng)的狀態(tài)。
history.replaceState()它和history.pushState()方法基本相同,區(qū)別只有一點(diǎn),history.replaceState()不會(huì)新生成歷史記錄,而是將當(dāng)前歷史記錄替換掉。
window.onpopstatepush的對(duì)立就是pop,可以猜到這個(gè)事件是在瀏覽器取出歷史記錄并加載時(shí)觸發(fā)的。但實(shí)際上,它的條件是比較苛刻的,幾乎只有點(diǎn)擊瀏覽器的“前進(jìn)”、“后退”這些導(dǎo)航按鈕,或者是由JavaScript調(diào)用的history.back()等導(dǎo)航方法,且切換前后的兩條歷史記錄都屬于同一個(gè)網(wǎng)頁(yè)文檔,才會(huì)觸發(fā)本事件。
上面的“同一個(gè)網(wǎng)頁(yè)文檔”請(qǐng)理解為JavaScript環(huán)境的document是同一個(gè),而不是指基礎(chǔ)URL(去掉各類(lèi)參數(shù)的)相同。也就是說(shuō),只要有重新加載發(fā)生(無(wú)論是跳轉(zhuǎn)到一個(gè)新站點(diǎn)還是繼續(xù)在本站點(diǎn)),JavaScript全局環(huán)境發(fā)生了變化,popstate事件都不會(huì)觸發(fā)。
popstate事件是設(shè)計(jì)出來(lái)和前面的2個(gè)方法搭配使用的。一般只有在通過(guò)前面2個(gè)方法設(shè)置了同一站點(diǎn)的多條歷史記錄,并在其之間導(dǎo)航(前進(jìn)或后退)時(shí),才會(huì)觸發(fā)這個(gè)事件。同時(shí),前面2個(gè)方法所設(shè)置的狀態(tài)對(duì)象(第1個(gè)參數(shù)),也會(huì)在這個(gè)時(shí)候通過(guò)事件的event.state返還回來(lái)。
此外請(qǐng)注意,history.pushState()及history.replaceState()本身調(diào)用時(shí)是不觸發(fā)popstate事件的。pop和push畢竟不一樣!
如何應(yīng)用HTML5 history API的內(nèi)容不多,具體如何應(yīng)用它來(lái)改進(jìn)Ajax翻頁(yè)呢?
首先,在服務(wù)器端添加對(duì)URL狀態(tài)參數(shù)的支持,例如?page=3將會(huì)輸出對(duì)應(yīng)頁(yè)碼的內(nèi)容(后端模板)。也可以是服務(wù)器端把對(duì)應(yīng)頁(yè)碼的數(shù)據(jù)給JavaScript,由JavaScript向頁(yè)面寫(xiě)入內(nèi)容(前端模板)。
接下來(lái),使用history.pushState(),在任一次翻頁(yè)的同時(shí),也設(shè)置正確的帶參數(shù)的URL。代碼可能是這樣:
newURL = "?page=" + pageNow; history.pushState(null, "", newURL);
到此,就解決了F5刷新?tīng)顟B(tài)還原的事了。
不過(guò),還沒(méi)有結(jié)束,在瀏覽器中點(diǎn)擊后退,例如從?page=3退到?page=2,會(huì)發(fā)現(xiàn)沒(méi)有變化。按道理說(shuō),這時(shí)候也應(yīng)該對(duì)應(yīng)變化。這就要用到popstate事件了。
為window添加popstate事件,加入這種導(dǎo)航變化時(shí)的處理。代碼可能是這樣(jQuery):
$(window).on("popstate", function(event) { // 取得之前通過(guò)pushState保存的state object,盡管本示例并不打算使用它。 // jQuery對(duì)event做了一層包裝,需要通過(guò)originalEvent取得原生event。 var state = event.originalEvent.state, // 本示例直接取URL參數(shù)來(lái)處理 reg = /page=(d+)/, regMatch = reg.exec(location.search), // 第1頁(yè)的時(shí)候既可以是 ?page=1,也可以根本沒(méi)有page參數(shù) pageNow = regMatch === null ? 1 : +regMatch[1]; updateByPage(pageNow); });
這樣,就完成了。這樣看起來(lái)是否會(huì)覺(jué)得還挺容易的呢?在支持HTML5 history API的瀏覽器中,以上部分就已經(jīng)做到了帶頁(yè)碼記錄的Ajax翻頁(yè)。
有待斟酌的兼容性問(wèn)題根據(jù)[caniuse][]上的數(shù)據(jù),IE10+及其他主流瀏覽器都支持HTML5 history API。為保證不支持的瀏覽器不報(bào)錯(cuò),可以加入是否支持HTML5 history API的判斷:
// 參考自 http://modernizr.com/download/#-history 源碼 var isHistoryApi = !!(window.history && history.pushState); // ... if(isHistoryApi){ // ... }
這樣,一個(gè)Ajax翻頁(yè),在支持HTML5 history API的瀏覽器上,將會(huì)智能地保存當(dāng)前頁(yè)碼信息,而不支持的瀏覽器仍然可以正常使用,只是不保存頁(yè)碼信息(就像改進(jìn)前那樣)。我認(rèn)為,按照“漸進(jìn)增強(qiáng)”的思路,這樣就是最好的了,也就是:只使用較少的代碼優(yōu)化高級(jí)瀏覽器的使用體驗(yàn)。
如果真的想要在各類(lèi)瀏覽器里都表現(xiàn)一致,擁有這樣的記錄功能呢?
這時(shí)候推薦使用Benjamin Lupton的[History.js][],它提供和HTML5 history API近似的api,會(huì)在不支持的瀏覽器里回退到hash形式去處理歷史記錄。盡管為了兼容這種hash的回退形式你可能要額外做點(diǎn)事(hash不會(huì)發(fā)送到服務(wù)器端),但它確實(shí)可以讓你做到更廣范圍的兼容。
HTML5 history API并不完美即使只考慮支持HTML5 history API的瀏覽器,它們對(duì)HTML5 history API的一些細(xì)節(jié)處理也會(huì)有差異和問(wèn)題。History.js提供的只針對(duì)HTML5瀏覽器的版本,仍然包含了不少處理兼容問(wèn)題的代碼。
但是,不完美也沒(méi)有關(guān)系。以我的測(cè)試結(jié)果,本文所介紹的簡(jiǎn)單的寫(xiě)法,就可以在絕大部分支持HTML5 history API的瀏覽器上正常運(yùn)行。如果你擔(dān)心有哪些瀏覽器會(huì)有潛在問(wèn)題,去測(cè)試那個(gè)瀏覽器就可以了。你最后用于兼容處理的自寫(xiě)代碼很可能遠(yuǎn)比一個(gè)JavaScript庫(kù)少得多,畢竟,你也不一定會(huì)喜歡額外引入一個(gè)JavaScript庫(kù)來(lái)完成一個(gè)功能吧。
一些相關(guān)內(nèi)容地址欄里的hash曾是過(guò)去被廣泛用來(lái)記錄頁(yè)面狀態(tài)的標(biāo)記,你可以閱讀[W3C Blog的這篇文章][]了解它的經(jīng)歷。
現(xiàn)在可以在不刷新的狀況下操作瀏覽器地址欄和歷史記錄了,那同一站點(diǎn)的普通鏈接跳轉(zhuǎn)是否都可以轉(zhuǎn)變?yōu)锳jax來(lái)提升使用體驗(yàn)?是的,而且已經(jīng)有了pjax[]這些專(zhuān)門(mén)完成這個(gè)功能的作品。
不只是翻頁(yè),HTML5 history API將尤其適合用在大量使用Ajax、包含多個(gè)視圖的單頁(yè)應(yīng)用。
為一個(gè)頁(yè)面的每一個(gè)狀態(tài)都生成一條歷史記錄不一定合適(會(huì)讓用戶(hù)的歷史記錄變多變亂),酌情使用replaceState()而不是pushState()來(lái)控制歷史記錄的數(shù)量。
結(jié)語(yǔ)HTML5 history API簡(jiǎn)單易學(xué),不多的幾行代碼就可以做到“狀態(tài)記錄”這個(gè)小小的改進(jìn),如果可以由你選擇“漸進(jìn)增強(qiáng)”,它還真的可以上線(xiàn)!
(重新編輯自我的博客,原文地址:http://acgtofe.com/posts/2014/12/play-with-browser-history)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/85445.html
摘要:但目前來(lái)看,單頁(yè)應(yīng)用在技術(shù)實(shí)現(xiàn)和體驗(yàn)上還有更大的發(fā)展空間,而這就是所要推進(jìn)的。模塊化頁(yè)面模塊化單頁(yè)應(yīng)用的特點(diǎn)之一是將頁(yè)面劃分為多個(gè)模塊,跳轉(zhuǎn)時(shí)更新模塊的內(nèi)容。與其他單頁(yè)庫(kù)相比,它們的職責(zé)更清晰,也易于理解。 showImg(https://segmentfault.com/img/bV2wO3?w=792&h=303);單頁(yè)Web應(yīng)用作為新一代Web模式,為用戶(hù)提供了更流暢的體驗(yàn)滿(mǎn)足感...
摘要:但目前來(lái)看,單頁(yè)應(yīng)用在技術(shù)實(shí)現(xiàn)和體驗(yàn)上還有更大的發(fā)展空間,而這就是所要推進(jìn)的。模塊化頁(yè)面模塊化單頁(yè)應(yīng)用的特點(diǎn)之一是將頁(yè)面劃分為多個(gè)模塊,跳轉(zhuǎn)時(shí)更新模塊的內(nèi)容。與其他單頁(yè)庫(kù)相比,它們的職責(zé)更清晰,也易于理解。 showImg(https://segmentfault.com/img/bV2wO3?w=792&h=303);單頁(yè)Web應(yīng)用作為新一代Web模式,為用戶(hù)提供了更流暢的體驗(yàn)滿(mǎn)足感...
摘要:但目前來(lái)看,單頁(yè)應(yīng)用在技術(shù)實(shí)現(xiàn)和體驗(yàn)上還有更大的發(fā)展空間,而這就是所要推進(jìn)的。模塊化頁(yè)面模塊化單頁(yè)應(yīng)用的特點(diǎn)之一是將頁(yè)面劃分為多個(gè)模塊,跳轉(zhuǎn)時(shí)更新模塊的內(nèi)容。與其他單頁(yè)庫(kù)相比,它們的職責(zé)更清晰,也易于理解。 showImg(https://segmentfault.com/img/bV2wO3?w=792&h=303);單頁(yè)Web應(yīng)用作為新一代Web模式,為用戶(hù)提供了更流暢的體驗(yàn)滿(mǎn)足感...
閱讀 1034·2023-04-26 02:21
閱讀 2845·2021-09-24 09:47
閱讀 1640·2019-08-30 15:55
閱讀 2198·2019-08-30 14:01
閱讀 2353·2019-08-29 14:01
閱讀 2080·2019-08-29 12:46
閱讀 843·2019-08-26 13:27
閱讀 1977·2019-08-26 12:23