JavaScript不刷新實(shí)現(xiàn)瀏覽器的前進(jìn)后退功能
最近在學(xué)習(xí)backbone,學(xué)習(xí)理解backbone就要先理解spa,理解spa就要先了解單頁面應(yīng)用是如何做到頁面不刷新改變url的。
相較于不同頁面的跳轉(zhuǎn),AJAX可以說大大提高了用戶的瀏覽體驗(yàn),不用看到頁面切換之間的白屏是件很愜意的事情。但是很多早先的AJAX應(yīng)用是不支持瀏覽器的前進(jìn)后退的,這導(dǎo)致了用戶不管在網(wǎng)站里瀏覽到何處,一旦刷新就會(huì)立刻回到起初的位置,并且用戶也無法通過瀏覽器的前進(jìn)后退按鈕來實(shí)現(xiàn)瀏覽歷史的切換。
對(duì)于第一個(gè)問題,解決還算容易,只要用cookie或者localStorage來記錄應(yīng)用的狀態(tài)即可,刷新頁面時(shí)讀取一下這個(gè)狀態(tài),然后發(fā)送相應(yīng)ajax請(qǐng)求來改變頁面即可。但是第二個(gè)問題就很麻煩了,先說下現(xiàn)代瀏覽器的解決方案。
HTML5 解決方案
要了解HTML5如何實(shí)現(xiàn)前進(jìn)后退,就要先了解下history對(duì)象和location對(duì)象。
history對(duì)象
History 對(duì)象屬性
1.length:返回瀏覽器歷史列表中的URL數(shù)量,用戶在當(dāng)前標(biāo)簽每訪問一個(gè)頁面,此數(shù)量加1。因?yàn)殡[私原因,URL具體內(nèi)容不可見。
2.state:與當(dāng)前網(wǎng)址相關(guān)的對(duì)象,只能通過pushState和replaceState添加或修改。我們可以可以用它來存儲(chǔ)跟url有關(guān)的信息。
History 對(duì)象方法
1.history.back()
此方法無參數(shù),觸發(fā)后會(huì)返回前一個(gè)瀏覽的頁面,相當(dāng)于點(diǎn)擊了瀏覽器的后退按鈕。
2.history.forward()
此方法無參數(shù),觸發(fā)后會(huì)返回后退前瀏覽的頁面,相當(dāng)于點(diǎn)擊了瀏覽器的前進(jìn)按鈕。
3.history.go(number)
此方法接受一個(gè)整形變量參數(shù),history.go(-1)相當(dāng)于后退一頁,history.go(1)相當(dāng)于前進(jìn)一頁,history.go(0)會(huì)刷新當(dāng)前頁面。
4.history.pushState(state, title, url)
改變url且不刷新頁面的關(guān)鍵就是它了,此方法會(huì)改變當(dāng)前頁面的location.href并且修改當(dāng)前的history.state對(duì)象,執(zhí)行后history.length會(huì)增加1。此方法接受三個(gè)參數(shù),
1.state:當(dāng)前網(wǎng)址相關(guān)的對(duì)象。
2.title:頁面標(biāo)題,但是所有瀏覽器都忽略它,要改變標(biāo)題還是要用document.title。
3.url:一個(gè)與當(dāng)前頁面同域的網(wǎng)址,location.href會(huì)變成此值。
5.history.replaceState(state, title, url)
此方法同上,但是它不會(huì)改變history.length,只會(huì)修改當(dāng)history.state和location.href。
注意pushState和replaceState第三個(gè)參數(shù)不可跨域,并且不會(huì)觸發(fā)瀏覽器的popstate事件和onhashchange事件(chrome33下測(cè)試)。
location對(duì)象
除了點(diǎn)擊前進(jìn)/后退按鈕和history事件,還可以通過location的方法和修改location的屬性來改變Url:
location對(duì)象的屬性(讀寫):
1.host:域名+端口號(hào)
2.hostname:域名
3.port:端口號(hào)
4.protocol:協(xié)議
5.href:完整路徑
6.origin:協(xié)議+域名+端口
7.hash:井號(hào) (#) 開始的 URL(hash)
8.pathname:文檔路徑+文檔名
9.search:(?)后面的內(nèi)容
可以通過改變location.href或location.hash來達(dá)到無刷新的目的。
location對(duì)象的方法:
1.assign:改變url的值,并且將當(dāng)前的url添加到歷史記錄中history.length會(huì)增加1。location.assig(‘#' + x)會(huì)改變url但是不刷新頁面。
2.reload:刷新頁面。
3.replace:改變url的值,但是history.length不變。使用方法同assign。
popstate事件
當(dāng)url改變時(shí),比如用戶點(diǎn)擊前進(jìn)/后退按鈕,history.go(n)(n不等于0),location.hash = x(x不等于當(dāng)前的location.hash)都會(huì)觸發(fā)此事件??梢杂盟鼇肀O(jiān)聽url,來實(shí)現(xiàn)各種功能。
window.onpopstate = function(){
//do sth
}
onhashchange事件
改變hash值會(huì)觸發(fā)popstate事件,而觸發(fā)popstate事件不一定會(huì)觸發(fā)onhashchange事件。經(jīng)過測(cè)試:
1.hash改變但是location.pathname不變會(huì)觸發(fā)onhashchange事件,比如history.pushState(”, ”, ‘#abc');
2.hash和location.pathname一起改變則不觸發(fā),比如history.pushState(”, ”, ‘a(chǎn)#abc');
老舊瀏覽器的寫法
老舊瀏覽器也不支持pushState和replaceState,所以通過popstate(事實(shí)上也不支持這個(gè)方法)監(jiān)聽url變化的路走不通。那么只能通過改變url#后面的內(nèi)容來達(dá)到無刷新,但是它們又不支持onhashchange,所以對(duì)url的變化是無動(dòng)于衷的(除了頁面會(huì)滾動(dòng)至頁面對(duì)應(yīng)id的位置)。那么只能祭出大招:輪詢,起一個(gè)setInterval來監(jiān)聽url的值。Like this:
var prevHash = window.location.hash;
var callback = function(){...}
window.setInterval(function() {
if (window.location.hash != prevHash) {
prevHash = window.location.hash;
callback(prevHash);
}
}, 100);
當(dāng)然這樣寫非常非常挫,如果不考慮點(diǎn)擊頁面帶有id的a標(biāo)簽來改變hash的情況,可以利用設(shè)計(jì)模式來優(yōu)雅的實(shí)現(xiàn)監(jiān)聽url。比如經(jīng)典的觀察者模式,專門用一個(gè)類來實(shí)現(xiàn)改變hash的功能,然后所有要監(jiān)聽url變化的類(觀察者)去訂閱這個(gè)(被觀察者)類。
//改變url的類
function UrlChanger() {
var _this = this;
this.observers = [];
//添加觀察者
this.addObserver = function(obj) {...}
//刪除觀察者
this.deleteObserver = function(obj) {...}
//通知觀察者
this._notifyObservers = function() {
var length = _this.observers.length;
console.log(length)
for(var i = 0; i < length; i++) {
_this.observers[i].update();
}
}
//改變url
this.changeUrl = function(hash) {
window.location.hash = hash;
_this._notifyObservers();
}
}
//監(jiān)聽類
function oneOfObservers() {
var _this = this;
this.update = function() {...}
}
//實(shí)現(xiàn)
var o1 = new UrlChanger();
var o2 = new oneOfObservers();
o1.addObserver(o2);
o1.changeUrl('fun/arg1/arg2/');
//o2 has do sth...
相關(guān)文章
實(shí)例講解javascript實(shí)現(xiàn)異步圖片上傳方法
給大家詳細(xì)講解一下如何通過javascript寫出異步圖片上傳,并且把實(shí)例代碼給大家分享了下,有興趣的讀者們測(cè)試一下吧。2017-12-12document.body.scrollTop 值總為0的解決方法 比較常見的標(biāo)準(zhǔn)問題
頁面具有 DTD(或者說指定了 DOCTYPE)時(shí),使用 document.documentElement。2009-11-11微信小程序使用checkbox顯示多項(xiàng)選擇框功能【附源碼下載】
這篇文章主要介紹了微信小程序使用checkbox顯示多項(xiàng)選擇框功能,涉及相關(guān)事件綁定與元素遍歷操作技巧,并附帶源碼供讀者下載參考,需要的朋友可以參考下2017-12-12微信小程序使用input組件實(shí)現(xiàn)密碼框功能【附源碼下載】
這篇文章主要介紹了微信小程序使用input組件實(shí)現(xiàn)密碼框功能,涉及input組件布局設(shè)置相關(guān)操作技巧,并附帶源碼供讀者下載參考,需要的朋友可以參考下2017-12-12uniapp實(shí)現(xiàn)可以左右滑動(dòng)導(dǎo)航欄
這篇文章主要為大家詳細(xì)介紹了uniapp 實(shí)現(xiàn)可以左右滑動(dòng)導(dǎo)航欄,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-10-10javascript Xml增刪改查(IE下)操作實(shí)現(xiàn)代碼
比較不錯(cuò)的實(shí)現(xiàn)代碼,大家可以仔細(xì)的看下,思路。2009-01-01