PushState+Ajax實現簡單的單頁面應用SPA例子

來源:互聯網
上載者:User

單頁面應用(Single Page Application)簡稱SPA,使用SPA構建的應用優點有使用者體驗好、速度快,內容的改變不需要重新載入整個頁面,避免了不必要的跳轉和重複渲染,從而相對減輕了伺服器壓力,SPA在WEB移動端應用非常廣泛。


我們在上一篇文章Javascript實現前端簡單路由中提到的前端路由,可以在不重新整理整個頁面的情況下,通過變換地址欄的hash來實現頁面局部載入。
今天我要給大家介紹的是使用HTML5的PushState+ajax實現不重新整理整個頁面,而地址欄變換,頁面局部重新整理的效果,綜合前後端頁面技術實現一個簡單的SPA。我們先來瞭解幾個知識點。
HTML5 History API
HTML5在History裡增加了pushState方法,這個方法會將當前的url添加到記錄中,然後修改當前url為新url。當然這個方法只會修改地址欄的Url顯示,但並不會發出任何請求。因此我們可以利用這個方法結合ajax實現單頁面應用SPA,就是PushState+Ajax,人稱Pjax。
pushstate的使用方法:
history.pushState(state, title, url)
state: 可以放任意你想放的資料,它將附加到新url上,作為該頁面資訊的一個補充。
title: 顧名思義,就是document.title。
url: 新url,也就是你要顯示在地址欄上的url。
history.replaceState(state, title, url)
replaceState方法與pushState大同小異,區別只在於pushState會將當前url添加到記錄,之後再修改url,而replaceState只是修改url,不添加記錄。
window.onpopstate
一般來說,每當url變動時,popstate事件都會被觸發。但若是調用pushState來修改url,該事件則不會觸發,因此,我們可以把它用作瀏覽器的前進後退事件。該事件有一個參數,就是上文pushState方法的第一個參數state。
Pjax能做什麼
Pjax是一個優秀的解決方案,它可以做:
可以在頁面切換間平滑過渡,增加Loading動畫。
可以在各個頁面間傳遞資料,不依賴URL。
可以選擇性的保留狀態,如音樂網站,切換頁面時不會停止播放歌曲。
所有的標籤都可以用來跳轉,不僅僅是a標籤。
避免了公用JS的反覆執行,減少了請求體積,節省流量,加快頁面響應速度。
對SEO也不會有影響,對於不支援HTML5的瀏覽器以及搜尋引擎爬蟲,則可以跳轉真實的頁面。
支援瀏覽器前進和後退按鈕。
實現原理
1. 攔截a標籤的預設跳轉動作。
2. 使用Ajax請求新頁面。
3. 將返回的Html替換到頁面中。
4. 使用HTML5的History API或者Url的Hash修改Url。
代碼實現
HTML
我們設定一個菜單#nav,通過點擊菜單上的連結,將連結頁面對應的內容載入到div#result中。
<ul id="nav"> 
    <li><a href="home.html">首頁</a></li> 
    <li><a href="product.html">產品</a></li> 
    <li><a href="server.php" title="服務">服務</a></li> 
</ul>
<div id="result"></div>
pjax.js
首先在pjax.js中判斷瀏覽器對html5的支援情況,然後定義一個cache緩衝對象:cache{},定義設定cache和擷取cache的方法。然後定義event事件對象:event{},綁定popstate和hashchange以及click事件,click事件會觸發調用pajax對象,請求頁面內容。cache緩衝對象和event事件對象的代碼大家可以下載源碼查看,本文由於篇幅原因只將核心pjax{}對象代碼粘出來。
var pjax = {
    // Forward And Back,表示當前操作是否由前進和後退觸發
    fnb: false,
    // 顯示新頁面內容
    show: function (title, html) {
        document.title = title;
        document.querySelector('#result').innerHTML = html;
    },
 
    //跳轉到指定頁面
    jump: function (url, data, callback) {
        
        // 如果是由前進後退觸發,則試著從緩衝中擷取資料
        if (pjax.fnb) {
            var value = cache.get(url);
            if (value !== null) {
                pjax.show(value.title, value.html);
                return;
            }
        }
 
 
        document.querySelector('#result').innerHTML = '載入中...';
        //ajax發送請求
        var xhr = new XMLHttpRequest();
 
        xhr.open("GET", url, true);
        xhr.setRequestHeader("X-PJAX", "true");
        xhr.setRequestHeader("X-PJAX-TITLE", data);
        xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
        xhr.onreadystatechange = function(){
            if(xhr.readyState === 4){
                if(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304){ //304是緩衝
                    var html = xhr.responseText,
                        title = xhr.getResponseHeader("X-PJAX-TITLE");
                    if(title==null){
                        title = document.title;
                    }else{
                        title = decodeURI(title);
                    }
                    //console.log(title);
                    
                    // 顯示新頁面
                    pjax.show(title, html);
 
                    //不是前進和後退按鈕觸發
                    if(!pjax.fnb){
                        // 修改URL,URL地址欄會變換
                        if (support === 'HTML5') {
                            history.pushState(null, null, url);
                        } else {
                            var path = url.replace(location.protocol + "//" + location.host, "");
                            location.hash = path;
                        }
                        // 添加到緩衝
                        cache.set(url, {
                            title: title,
                            html: html
                        });
                    }
 
                }else{
                    console.log('請求失敗!');
                }
                pjax.fnb = true;
            }
        };
        xhr.send();
    },
 
    init: function () {
        event.bindEvent();
    }
};
可以看出,pjax的核心部分是發送非同步ajax請求,調用html5的history.pushState() 方法,快取頁面面資訊,已經處理非同步請求返回的結果。
最後調用:
pjax.init();
好了,以上是一個簡單的單頁面執行個體,代碼顯得有點粗糙,歡迎大家指正並最佳化,接下來我會有文章和大家分享幾個常見的前端架構實現的優雅的單頁面應用執行個體,敬請關注。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.