萬盛學電腦網

 萬盛學電腦網 >> 腳本專題 >> javascript >> JavaScript不刷新實現浏覽器的前進後退功能

JavaScript不刷新實現浏覽器的前進後退功能

 相較於不同頁面的跳轉,AJAX可以說大大提高了用戶的浏覽體驗,不用看到頁面切換之間的白屏是件很惬意的事情。但是很多早先的AJAX應用是不支持浏覽器的前進後退的,這導致了用戶不管在網站裡浏覽到何處,一旦刷新就會立刻回到起初的位置,並且用戶也無法通過浏覽器的前進後退按鈕來實現浏覽歷史的切換。

對於第一個問題,解決還算容易,只要用cookie或者localStorage來記錄應用的狀態即可,刷新頁面時讀取一下這個狀態,然後發送相應ajax請求來改變頁面即可。但是第二個問題就很麻煩了,先說下現代浏覽器的解決方案。

HTML5 解決方案

要了解HTML5如何實現前進後退,就要先了解下history對象和location對象。

history對象

History 對象屬性

1.length:返回浏覽器歷史列表中的URL數量,用戶在當前標簽每訪問一個頁面,此數量加1。因為隱私原因,URL具體內容不可見。
2.state:與當前網址相關的對象,只能通過pushState和replaceState添加或修改。我們可以可以用它來存儲跟url有關的信息。

History 對象方法

1.history.back()

此方法無參數,觸發後會返回前一個浏覽的頁面,相當於點擊了浏覽器的後退按鈕。

2.history.forward()

此方法無參數,觸發後會返回後退前浏覽的頁面,相當於點擊了浏覽器的前進按鈕。

3.history.go(number)

此方法接受一個整形變量參數,history.go(-1)相當於後退一頁,history.go(1)相當於前進一頁,history.go(0)會刷新當前頁面。

4.history.pushState(state, title, url)

改變url且不刷新頁面的關鍵就是它了,此方法會改變當前頁面的location.href並且修改當前的history.state對象,執行後history.length會增加1。此方法接受三個參數,

1.state:當前網址相關的對象。
2.title:頁面標題,但是所有浏覽器都忽略它,要改變標題還是要用document.title。
3.url:一個與當前頁面同域的網址,location.href會變成此值。

5.history.replaceState(state, title, url)

此方法同上,但是它不會改變history.length,只會修改當history.state和location.href。

注意pushState和replaceState第三個參數不可跨域,並且不會觸發浏覽器的popstate事件和onhashchange事件(chrome33下測試)。

location對象

除了點擊前進/後退按鈕和history事件,還可以通過location的方法和修改location的屬性來改變Url:

location對象的屬性(讀寫):

1.host:域名+端口號
2.hostname:域名
3.port:端口號
4.protocol:協議
5.href:完整路徑
6.origin:協議+域名+端口
7.hash:井號 (#) 開始的 URL(hash)
8.pathname:文檔路徑+文檔名
9.search:(?)後面的內容

可以通過改變location.href或location.hash來達到無刷新的目的。

location對象的方法:

1.assign:改變url的值,並且將當前的url添加到歷史記錄中history.length會增加1。location.assig(‘#' + x)會改變url但是不刷新頁面。
2.reload:刷新頁面。
3.replace:改變url的值,但是history.length不變。使用方法同assign。

popstate事件

當url改變時,比如用戶點擊前進/後退按鈕,history.go(n)(n不等於0),location.hash = x(x不等於當前的location.hash)都會觸發此事件。可以用它來監聽url,來實現各種功能。

代碼如下:
    window.onpopstate = function(){
        //do sth
    }

 

onhashchange事件

改變hash值會觸發popstate事件,而觸發popstate事件不一定會觸發onhashchange事件。經過測試:

1.hash改變但是location.pathname不變會觸發onhashchange事件,比如history.pushState(”, ”, ‘#abc');
2.hash和location.pathname一起改變則不觸發,比如history.pushState(”, ”, ‘a#abc');

老舊浏覽器的寫法

老舊浏覽器也不支持pushState和replaceState,所以通過popstate(事實上也不支持這個方法)監聽url變化的路走不通。那麼只能通過改變url#後面的內容來達到無刷新,但是它們又不支持onhashchange,所以對url的變化是無動於衷的(除了頁面會滾動至頁面對應id的位置)。那麼只能祭出大招:輪詢,起一個setInterval來監聽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);

 

當然這樣寫非常非常挫,如果不考慮點擊頁面帶有id的a標簽來改變hash的情況,可以利用設計模式來優雅的實現監聽url。比如經典的觀察者模式,專門用一個類來實現改變hash的功能,然後所有要監聽url變化的類(觀察者)去訂閱這個(被觀察者)類。

 

 代碼如下:
//改變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();
    }
}
//監聽類
function oneOfObservers() {
    var _this = this;
    this.update = function() {...}
}
//實現
var o1 = new UrlChanger();
var o2 = new oneOfObservers();
o1.addObserver(o2);
o1.changeUrl('fun/arg1/arg2/');
//o2 has do sth...
copyright © 萬盛學電腦網 all rights reserved