首頁  >  文章  >  类库下载  >  利用pushState, popState和location.hash等方法自己實作一個小型路由

利用pushState, popState和location.hash等方法自己實作一個小型路由

高洛峰
高洛峰原創
2016-10-31 14:00:492171瀏覽

這篇文章主要是記錄下HTML5中history提供的pushState, replaceStateAPI。最後透過這些API自己實現小型的路由。

關於window.history提供的API請參閱Mozilla文檔

其中history提供的pushState和replaceState2個API提供了操作瀏覽器歷史堆疊的方法。

其中pushState:

history.pushState(data, null, '#/page=1');
    
    pushState接收3个参数,第一个参数为一个obj,表示浏览器
    
    第二个参数是document.title的值,一般设定为`null`
    
    第三个参数string,用以改变 当前url

pushState方法在改變url的同時向瀏覽器歷史堆疊中壓入新的歷史記錄。

接收url的參數為string類型,用以改變當前地址欄的url.需要注意的一點就是這個參數不能和跨域,即協議,域名,端口必須都是相同的,如果出現跨域的情況,即會提示:

Uncaught DOMException: Failed to execute 'pushState' on 'History': A history state object with URL 'http://www.baidu.com/' cannot be created in a document with origin 'http://commanderXL.com' and URL

Example:

打开www.baidu.com

    history.pushState(null, null, '?page=1')    //地址栏变成 www.baidu.com/?page=1
    
    history.pushState(null, null, '#page=2');    //地址栏变成 www.baidu.com/#page=2

其中replaceState:

history.replaceState(null, null, '#page=2');

replaceState接收的參數pushState相同,但是最終的效果是:地址列url會根據接收到的參數而變化,但是瀏覽器並未在當瀏覽器歷史棧中增加瀏覽器的歷史記錄,而是取代目前的瀏覽器歷史記錄。

透過pushState和replaceState雖然能改變URL,但是不會主動觸發瀏覽器reload。

window物件也提供popstate方法:

window.addEventListener('popstate', function() {
        
    });

這個方法用以監聽瀏覽器在不同歷史記錄中進行切換,而觸發對應的事件。

在瀏覽器提供的history物件上還有go, back方法,用以模擬使用者點擊瀏覽器的前進後退按鈕。在某個web應用程式當中,例如點擊了標籤,發生了頁面的跳躍。這時呼叫history.back();方法後頁面回退,同時頁面發生刷新,這時window.onpopstate無法監聽這個事件。但如果是透過pushState或replaceState來改變URL且不發生瀏覽器刷新的話,再使用history.back()或history.go(),這樣popstate事件會被觸發。

history.pushState({page: 1}, null, '?page=1');
    history.pushState({page: 2}, null, '?page=2');

    history.back(); //浏览器后退

    window.addEventListener('popstate', function(e) {        //在popstate事件触发后,事件对象event保存了当前浏览器历史记录的状态.
        //e.state保存了pushState添加的state的引用
        console.log(e.state);  //输出 {page: 1}
    });

PS: 透過pushState在url上新增?page=1可以透過location.search去取得search的內容。不過如果透過location.search去改變url的話是會主動觸發瀏覽器reload的。這個特性可以和下面將的關於hash的內容比較下。

API大致了解了,那麼這些方法可以運用到哪些地方呢?一個比較常用的場景是就在單頁應用中,透過這些API完成前端的路由設計,利用pushState, replaceState可以改變url同時瀏覽器不刷新,並且透過popstate監聽瀏覽器歷史記錄的方式,完成一系列的異步動作。

addRoute('/login', function() {
        //do something
    })
    
    
    //路由处理
    const routeHandle = (path) => {
        Router.forEach((item, index) => {
            if(item.path === path) {
                item.handle.apply(null, [path]);
                return true;
            }
        })
        return false;
    }
    
    
    //拦截默认的a标签行为
    document.addEventListener('click', function(e) {
        let dataset = e.target.dataset;
        if(dataset) {
            if(routeHandle(dataset.href)) {
                //阻止默认行为
                e.preventDefault();
            }
        }
    })

大致的實現思路就是,透過添加路由訊息,然後攔截標籤的預設行為,並與註冊的路由資訊進行匹配。若符合成功呼叫對應的handle方法.

不過pushState和replaceState方法在低版本的IE瀏覽器下相容性不是很好。所以可以進行降級使用hash來進行路由設計。

hash?請戳我。

可以透過location.hash取得url上第一個#(fragment)及後面的內容。同時也能透過location.hash改寫其內容,且不會主動觸發瀏覽器reload。 有些功能是不是跟pushState和replaceState一樣? 所以為了相容到低版本的瀏覽器,可以透過監聽#變化來進行路由設計。

那麼如何去監聽呢? 比較粗暴的一種方式就是polling。

var oldHash = location.hash;
    setTimeInterval(function() {        if(oldHash !== location.hash) {            
            //do something
        
            oldHash = location.hash;
        }
    }, 100);

不過,H5也提供了一個API: hashchange。它的就可以直接取代上面的polling方法,來監聽#的變化。

window.addEventListener('hashchange', function() {
        routeHandle(locaiton.hash);
    });

這個小型的路由設計可以參考我的github.

稍微總結下:

上面主要介紹了history提供的一些API,hash的相關知識。在平時可以運用到SPA當中,Gmail就是透過hash來進行路由設計的。它相對於頁面跳轉來說:

頁面只需要載入一次。後面的頁面切換可以透過ajax去請求資料。頁面體驗更加流暢;

可以利用本地緩存,優化頁面體驗。在不同頁面切換的過程中更加流暢;

可進行隨選載入...

等等一些實用的好處吧。

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

相關文章

看更多