關於單頁應用
單頁Web應用(single page web application,SPA),就是只有一張Web頁面的應用,是加載單個HTML 頁面並在用戶與應用程序交互時動態更新該頁面的Web應用程序。簡單來說就是用戶只需要加載一次頁面就可以不再請求,當點擊其他子頁面時只會有相應的URL改變而不會重新加載。
單頁應用的實現
如果你的項目涉及到單頁面的話,路由是必不可少的。從上面的介紹中可以知道單頁應用的實現依賴與路由,在這里我們可以將上面路由的過程分為兩部分:
- 更新URL頁面不刷新
ps: 之前面試被問到過這個問題,現在才恍然大悟面試官大大想要問的是這個點。 ==。 - 監聽URL的變化,執行頁面替換邏輯
實現改變URL頁面不刷新
按照常規的邏輯我們切換URL好像就會跳轉網頁,但是轉念一項錨鏈接的URL不是也改變了嗎? 這里,存在兩種滿足需求的方式。
- 利用URL中的hash方式
了解http協議就會知道,url的組成部分有很多,譬如協議、主機名、資源路徑、查詢字段等等,其中包含一個稱之為片段的部分,以“#”為標識。打開控制台,輸入 location.hash,你可以得到當前url的hash部分(如果當前url不存在hash則返回空字符串)。接下來,輸入 location.hash = '123',會發現瀏覽器地址欄的url變了,末尾增加了’#123’字段,並且,頁面沒有被重新刷新。很顯然,這很符合我們的要求。 - 利用H5的history API
html5引入了一個history對象,包含了一套訪問瀏覽器歷史的api,可以通過window.history訪問到它。 HTML5 History API包括2個方法:history.pushState()和history.replaceState(),和1個事件:window.onpopstate。這兩個方法都是對瀏覽器的歷史棧進行操作,將傳遞的url和相關數據壓棧,並將瀏覽器地址欄的url替換成傳入的url且不刷新頁面,而且他們的參數也相同,第一個參數用於存儲該url對應的狀態對象,該對象可在onpopstate事件中獲取,也可在history對象中獲取。第二個參數是標題,目前瀏覽器並未實現。第三個參數則是設定的url。一般設置為相對路徑,如果設置為絕對路徑時需要保證同源。。不同的是pushState 將指定的url直接壓入歷史記錄棧頂,而 replaceState 是將當前歷史記錄棧頂替換成傳入的數據。不過低版本對history AIP的兼容性不是很好。
監聽URL的變化,執行頁面替換邏輯
- 對於hash方式,我們通常采用監聽hashchange事件,在事件回調中處理相應的頁面視圖展示等邏輯。在不支持hashchange事件的瀏覽器中,我們只能通過setInterval設置來模擬hashchange(不停的對比URL如果有改變)。
var oldHash = location.hash; var oldURL = location.href; setInterval (function () { var newHash = location.hash; var newURL = location.herf; if (newHash !== oldHash && typeof window.onhashchange === 'function') { // 這里執行onhashchange的回調 } }, 100)
- 采用history API的形式時,需要觸發onpopstate,popstate 事件只會在瀏覽器某些行為下觸發, 比如點擊后退按鈕(或者在JavaScript中調用 history.back() 方法)。這也就是說,我們在使用history API改變瀏覽器的url時,仍需要額外的步驟去觸發 popstate 事件,例如調用 history.back() 會 history.forward() 等方法
兩種實現的比較
總的來說,基於Hash的路由,兼容性更好;基於History API的路由,更加直觀和正式。但是,有一點很大的區別是,基於Hash的路由不需要對服務器做改動,基於History API的路由需要對服務器做一些改造。