使用HTML5的History API

来源:http://www.cnblogs.com/jaxu/archive/2016/08/07/5745191.html
-Advertisement-
Play Games

HTML5 History API提供了一種功能,能讓開發人員在不刷新整個頁面的情況下修改站點的URL。這個功能很有用,例如通過一段JavaScript代碼局部載入頁面的內容,你希望通過改變當前頁面的URL來反應出頁面內容的變化,這時該功能可以派上用場。 舉個例子,當用戶從首頁進入幫助頁面時,我們通 ...


  HTML5 History API提供了一種功能,能讓開發人員在不刷新整個頁面的情況下修改站點的URL。這個功能很有用,例如通過一段JavaScript代碼局部載入頁面的內容,你希望通過改變當前頁面的URL來反應出頁面內容的變化,這時該功能可以派上用場。

  舉個例子,當用戶從首頁進入幫助頁面時,我們通過Ajax來載入幫助頁面的內容。然後這個用戶又轉到產品頁面,我們需要再一次通過Ajax請求來替換頁面的內容。當用戶想分享頁面的URL時,通過History API,我們可以改變頁面的URL來反應內容的修改,這樣不管是用戶分享還是保存的URL都能和頁面的內容對應起來。

基本知識

  要查看這個API提供了哪些功能非常簡單,打開瀏覽器的Developer Tools工具面板,然後在console中輸入history。如果你的瀏覽器支持History API,你將會看到這個對象下麵附帶了很多方法。

  註意其中的pushStatereplaceState這兩個方法。我們可以在console中進行一些簡單的測試,來看看當我們使用這兩個方法時URL會發生什麼變化。稍後我們將分析這兩個方法中的所有參數,現在我們只需要關註最後一個參數:

history.replaceState(null, null, 'hello');

  上面代碼中的replaceState方法改變了當前頁面的URL,在後面添加了一個'/hello'。不過並沒有發出任何request請求,當前視窗仍然停留在之前的頁面。不過這裡有個問題,當你點擊瀏覽器的後退按鈕時,頁面並不會回退到我們通過replaceState方法修改之前的那個URL,而是直接回退到了上一個頁面(即我們進入到這個頁面之前的那個頁面)。這是因為replaceState方法不會修改瀏覽器的history,它只是簡單地替換了地址欄中的URL。

  要解決這個問題我們需要使用pushState方法:

history.pushState(null, null, 'hello');

  現在再點擊瀏覽器的後退按鈕,你會發現它和你預想的效果一樣。因為pushState方法將我們傳給它的URL添加到瀏覽器的history中,從而改變了瀏覽器的history。假如我們將另外一個完整的站點URL傳遞給它會發生什麼情況呢?例如我們在baidu.com的首頁進行測試,然後在console中輸入下麵的內容。

history.pushState(null, null, 'https://twitter.com/hello');

  瀏覽器會報錯。因為傳遞給pushState方法的URl必須和當前頁面的URL屬於同一個源(即不能跨域),否則會有很大的安全漏洞,開發人員可能會借用該功能來欺騙用戶,讓他們覺得自己是在訪問一個完全不同的站點,而事實並非如此。

  來看看傳遞給pushState方法的所有參數:

history.pushState([data], [title], [url]);
  1. 第一個參數用來傳遞我們需要的數據,當頁面的狀態發生變化時我們可以接收到該數據。如用戶點擊瀏覽器的後退和向前按鈕。需要註意的是在Firefox中只允許傳遞最多640K的數據。
  2. 第二個參數title是一個字元串,不過截止到目前,幾乎所有的瀏覽器都忽略該參數。
  3. 最後一個參數是我們想要替換的URL。

簡單回顧一下

  這些History API最主要的功能就是不重新載入頁面。以往我們只能通過改變window.location的值來修改當前頁面的URL,不過這會導致整個頁面被重新載入。如果你修改的只是URL中的hash,則不會導致頁面被刷新。 

  使用舊的hashbang方法可以改變頁面的URL而不刷新頁面。著名的Twitter就是使用的該方法,不過也廣受詬病,畢竟hash在location中並不被作為一個真正的資源來對待。

  作為History API的早期支持者,Twitter後來拋棄了傳統的hashbang方法。在2012年,Twitter的團隊介紹了他們的新方法,併列出了其中的一些問題同時還詳細地介紹了各瀏覽器應該如何實現該規範。

一個使用pushState和Ajax的例子

https://css-tricks.com/examples/State/

  在該示例中,我們希望用戶通過我們的網站找到電影捉鬼敢死隊(一部美國電影)中的演員。當用戶選擇一個圖片時,我們需要在下方顯示該演員對應的文字描述,同時給該圖片一個被選中的效果。當點擊後退按鈕時,頁面應該切換到上一個被選中的圖片狀態,同時圖片下方的文字也要一併切換。當點擊前進按鈕時也一樣。

  這裡有一個效果圖:

  這個示例的HTML代碼非常簡單:div.gallery中包含了所有的鏈接,每個鏈接里有一個圖片。接下來我們放置了一個空的div.content,用來存放當演員圖片被點擊時顯示在下放的文字。

<div class="gallery">
  <a href="https://cdn.css-tricks.com/peter.html">
    <img src="bill.png" alt="Peter" class="peter" data-name="peter">
  </a>
  <a href="https://cdn.css-tricks.com/ray.html">
    <img src="ray.png" alt="Ray" class="ray" data-name="ray">
  </a>
  <a href="https://cdn.css-tricks.com/egon.html">
    <img src="egon.png" alt="Egon" class="egon" data-name="egon">
  </a>
  <a href="https://cdn.css-tricks.com/winston.html">
    <img src="winston.png" alt="Winston" class="winston" data-name="winston">
  </a>
</div>

<p class="selected">Ghostbusters</p>
<p class="highlight"></p>

<div class="content"></div>

  如果沒有JavaScript該頁面仍然可以正常工作,點擊圖片可以跳轉到對應的頁面,然後點擊後退按鈕也可以回到之前的頁面。這是為了考慮頁面的可訪問行和優雅降級。

  接下來我們要添加JavaScript代碼了。我們通過event propagation給div.gallery元素中的每一個link添加一個事件處理程式,像這樣:

var container = document.querySelector('.gallery');

container.addEventListener('click', function(e) {
  if (e.target != e.currentTarget) {
    e.preventDefault();
    // e.target is the image inside the link we just clicked.
  }
  e.stopPropagation();
}, false);

  在if語句中,我們獲取到被選中圖片的data-name屬性的值,然後將'.html'添加到後面拼成一個要訪問的頁面地址,並將其作為第三個參數傳遞給pushState方法(不過在真實的例子中我們可能會在Ajax請求成功之後才會去修改URL)。

var data = e.target.getAttribute('data-name'),
url = data + ".html";
history.pushState(null, null, url);
    
// 此處更改當前的classes樣式
// 然後使用data變數的值更新
// 並通過Ajax請求.content元素的內容
// 最後再更新當前文檔的title

(當然,此處我們也可以直接使用link的href屬性的值)

  我將真實代碼中的內容都替換成註釋了,這樣我們可以只關註pushState方法的使用。

  現在我們點擊圖片,URL和Ajax請求的內容會被自動更新,但是當我們點擊後退按鈕時並不會回退到之前選中的演員圖片。這裡我們還需要在用戶點擊後退和前進按鈕時使用另外一個Ajax請求來更新內容,並再一次使用pushState方法來更新頁面的URL。

  我們使用pushState方法中的第一個參數(其中的state)來保存狀態信息:

history.pushState(data, null, url);

  上面代碼中的data參數在popstate事件觸發時可以被獲取到。當瀏覽器的後退和前進按鈕被點擊時會觸發popstate事件。

window.addEventListener('popstate', function(e) {
  // e.state表示上一個被點擊的圖片的data-attribute
});

  我們可以通過該參數傳遞一些我們需要的信息,例如在該示例中我們將之前選中的捉鬼敢死隊的演員作為參數傳遞給requestContent方法,在該方法中,我們使用jQuery的load方法進行一次Ajax請求。

function requestContent(file) {
  $('.content').load(file + ' .content');
}

window.addEventListener('popstate', function(e) {
  var character = e.state;

  if (character == null) {
    removeCurrentClass();
    textWrapper.innerHTML = " ";
    content.innerHTML = " ";
    document.title = defaultTitle;
  } else {
      updateText(character);
      requestContent(character + ".html");
      addCurrentClass(character);
      document.title = "Ghostbuster | " + character;
  }
});

  如果用戶點擊了演員Ray的圖片,event listener會被觸發,然後在pushState事件中保存圖片的data屬性的值。當用戶點擊另外一個圖片,並點擊了瀏覽器的後退按鈕,此時popstate事件會被觸發,從而重新載入ray.html頁面。

  這意味著什麼呢?當我們點擊一個演員的圖片然後將被更改的URL分享出去,用戶訪問這個URL時對應的HTML文件會被自動載入進來。這會帶來一些更好的用戶體驗,並保證了URL和頁面內容的一致性從而減少了因此而帶給用戶的一些困惑。

  上面的示例只是簡單地通過jQuery來動態載入內容,我們當然也可以在pushState方法中傳遞一些更加複雜的對象。不過這個例子已經能足夠說明問題並幫助我們開始學習如何使用History API的功能。我們先要學會走,然後才能跑。

下一步

  如果我們想大範圍地使用這種技術,我們應該考慮使用一些專有的工具,例如pjax 它是一個jQuery的插件,使用它可以大大提高我們同時使用Ajax和pushState方法進行開發的速度,不過它只支持那些使用History API介面的現代瀏覽器。

  History JS可以相容舊瀏覽器,對於不支持History API介面的瀏覽器,它依然使用舊的URL hash的方式來實現同樣的功能。

有關URLs

  這裡我特別引用了Kyle Neath有關URLs的說明:

URLs是一個通用的概念,它可以工作在Firefox, Chrome, Safari, Internet Explorer, curl, wget,甚至在你的iPhone, Android以及便簽紙上。它是web中的一個通用的語法。不要認為這是理所當然的。任何一個稍微懂點技術的用戶都可以瀏覽你的應用的90%以上的部分而不用去刻意記住那些URL的結構。要實現這樣的效果,你需要考慮URLs的實用性。

  這意味著不論你想要進行什麼樣的hacks或性能優化,作為web開發人員,你應該註重URL。而隨著HTML5 History API的幫助,我們可以輕鬆地解決諸如上述示例中的一些問題。

常見問題

  • 將Ajax請求的地址嵌入到a標記的href屬性中通常是個不錯的主意。
  • 確保在JavaScript的click事件處理程式中return true,這樣當有人使用中鍵點擊或命令點擊時不會導致程式被意外覆蓋。

補充

瀏覽器支持

ChromeSafariFirefoxOperaIEAndroidiOS
31+ 7.1+ 34+ 11.50+ 10+ 4.3+ 7.1+

原文地址:https://css-tricks.com/using-the-html5-history-api/


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 請註意以下要點: 1、是否開啟了認證,QQ郵箱、163郵箱均要開啟認證 2、javax.mail.MessagingException: Could not connect to SMTP host: smtp.163.com, port: 25; //連接超時 解決參考:將這個屬性的true加上引 ...
  • stdafx.h: Form1.h ...
  • 1.安裝 Erlang,官網:https://www.erlang.org/ 2.安裝RabbitMQ伺服器,rabbitMQ server,官網http://www.rabbitmq.com/ 註:可以根據不同的需要到官網進行相關下載!!! 3.安裝完成之後需要對其進行配置變數: 創建新的系統變數 ...
  • 最近想用C++在windows下實現一個基本的圖像查看器功能,目前只想到了使用GDI或OpenGL兩種方式。由於實在不想用GDI的API了,就用OpenGL的方式實現了一下基本的顯示功能。用GDAL讀取圖像,這樣就能與圖像格式無關。OpenGL的glDrawPixels()函數也能實現圖像顯示,但是... ...
  • 數組的定義: JavaScript 中的數組是一種特殊的對象,用來表示偏移量的索引是該對象的屬性,索引可能是整數。然而,這些數字索引在內部被轉換為字元串類型,這是因為 JavaScript 對象中的屬性名必須是字元串。在內部被歸類為數組。由於 Array 在 JavaScript 中被當作對象,因此 ...
  • 快速排序,又稱劃分交換排序。以分治法為策略實現的快速排序演算法。 本文主要要談的是利用javascript實現in-place思想的快速排序 分治法: 在電腦科學中,分治法是建基於多項分支遞歸的一種很重要的演算法範式。字面上的解釋是“分而治之”,就是把一個複雜的問題分成兩個或更多的相同或相似的子問題, ...
  • 看懂此文,不再困惑於 JS 中的事件設計 今天剛在關註的微信公眾號看到的文章,關於JS事件的,寫的很詳細也很容易理解,相關的知識點都有總結到,看完就有種很舒暢的感覺,該串起來的知識點都串起來了。反正一位元組:爽。 作者:aitangyong 鏈接:blog.csdn.net/aitangyong/ar ...
  • 在學習javascript中,如果在事件的使用上出現一些反差效果,不良效果,如滑鼠的移入移出時,顯示你所需要的內容, 但就是沒有出現,然而你不斷的檢查代碼,逐個代碼查錯,還在瀏覽器的調試工具中調試都沒有發現錯誤,沒有看到你所 想要的錯誤,那麼這個時候你要判斷一下是不是冒泡事件帶來的不良效果了,不過在 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...