閱讀459 返回首頁    go 阿裏雲 go 技術社區[雲棲]


不刷新改變/更換URL: pushState + Ajax

舊的解決方案

曾說SEO和ajax是天敵。此前從Twitter開始流行Ajax+hash的方式調用內容,Google給出的解決方案是“#!~string”自動轉換為“?_excaped_fragment_=~string”來抓取動態內容。但這無疑會非常麻煩:首先你需要對網站進行“?_excaped_fragment_=~string”的處理配置,而且,如果用戶把網址“https://example.com/#!/~string”直接複製並分享的話,意味著網頁還必須監聽hashchange。不過如果你覺得這個#!很好看就沒關係了。

twtter hash

新的解決方案: pushState

然而HTML5的新接口pushState / replaceState就可以比較完美的解決問題,它避免了改變hash的問題,避免了用戶不理解URL的形式感到疑惑,同時還有onpopstate提供監聽,良好響應後退前進。而且它不需要這個URL真實存在。

HTML5 的 pushState+Ajax

HTML5提供history接口,把URL以state的形式添加或者替換到瀏覽器中,其實現函數正是 pushState 和 replaceState。

pushState 例子

pushState() 的基本參數是:

window.history.pushState(state, title, url);

其中state和title都可以為空,但是推薦不為空,應當創建state來配合popstate監聽。

例如,我們通過pushState現改變URL而不刷新頁麵。

var state = ( {

url: ~href, title: ~title~additionalKEY~additionalVALUE

} );

window.history.pushState(state, ~title~href);

其中帶有“~”符號的是自定義內容。就可以把這個~href(URL)推送到瀏覽器的曆史裏。如果想要改變網頁的標題,應該:

document.title= ~newTitle;

注意隻是pushState是不能改變網頁標題的哦。

Demo 演示

 (實現函數onclick = history.pushState( null, null, '/test-string'); )。實際上這個博客在文章之間也部署了這個技術。

replaceState 同理

window.history.replaceState( state, ~title, ~href);

pushState、replaceState 的區別

pushState()可以創建曆史,可以配合popstate事件,而replaceState()則是替換掉當前的URL,不會產生曆史。

限製因素

隻能用同域的URL替換,例如你不能用https://baidu.com去替換https://google.com。而且state對象不存儲不可序列化的對象如DOM。

Ajax 配合 pushState 例子

現在用Ajax + pushState來提供全新的ajax調用風格。以jQuery為例,為了SEO需要,應該為a標簽的onclick添加方法。

$("~target a").click(function(evt){

evt.preventDefault(); // 阻止默認的跳轉操作

var uri=$(this).attr('href');

var newTitle=ajax_Load(uri); // 你自定義的Ajax加載函數,例如它會返回newTitle

document.title=newTitle; // 分配新的頁麵標題

if(history.pushState){

var state=({

url: uri, title: newTitle

});

window.history.pushState(statenewTitleuri);

}else{ window.location.href="#!"+~fakeURI; } // 如果不支持,使用舊的解決方案

return false;

});

function ajax_Load(uri){ ... return newTitle; } // 你自定義的ajax函數,例如它會返回newTitle

即可完成pushState。至於新標題newTitle的獲取就是另外的問題了,例如你可以為a標簽分配data-newtitle=~title屬性並屆時讀取,或者如果你用的$.ajax()函數,可以用$(result).filter("title").text()來獲取。

另外如果需要對新加載的頁麵的連接同樣使用這個ajax,則需要對新內容的a標簽重新部署,例如

$("~newContentTarget a").click(function(evt){ ... });

pushState 配合 popstate 監聽

想要良好的支持瀏覽器的曆史前進後退操作,應當部署popstate監聽:

window.addEventListener('popstate', function(evt){

var state = evt.state;

var newTitle = ajax_Load(state.url); //你自定義的ajax加載函數,例如它會返回newTitle

document.title=newTitle;

}, false);

提醒,你可以通過setRequestHeader()來讓服務器端配合你的ajax請求輸出專門的內容。

流程圖示意

這個例子的大致過程如下圖所示

ajax pushstate example

jQuery + PJAX 插件

已經在github上發布,有人把PJAX做成了jQuery插件,方便調用,節省大量代碼:

if ($.support.pjax) {

$(document).on('click', 'a[data-pjax]', function(event) {

var container = $(this).closest('[data-pjax-container]')

$.pjax.click(event, {container: container})

});}

謝謝收看,如有不正請指出。

轉自

https://blog.netsh.org/posts/pushstate-ajax_1339.netsh.html

最後更新:2017-04-03 12:53:59

  上一篇:go mysql修改root密碼、登錄、導入導出等命令小記
  下一篇:go USRP 問題——輸 出“O”“U”"u“”a"的意義