利用pushState, popState和location.hash等方法自己實現一個小型路由
這篇文章主要是記錄下HTML5中history提供的pushState
, replaceState
API。最後通過這些API自己實現小型的路由。
關於window.history提供的API請參見Mozilla文件
其中history
提供的pushState
和replaceState
2個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應用當中,比如點選了<a>
標籤,發生了頁面的跳轉。這時呼叫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
監聽瀏覽器歷史記錄的方式,完成一系列的非同步動作。
<a data-href="/post"></a>
<a data-href="/login"></a>
//路由
const Router = [];
const addRoute = (path = '', handle = () => {}) => {
let obj = {
path,
handle
}
Router.push(obj);
}
//新增路由定義
addRoute('/post', function() {
//do something
});
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();
}
}
})
大致的實現思路就是,通過<a>
新增路由資訊,然後攔截<a>
標籤的預設行為,並與註冊的路由資訊進行匹配。若匹配成功呼叫對應的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去請求資料。頁面體驗更加流暢;
-
可以利用本地快取,優化頁面體驗。在不同頁面切換的過程中更加流暢;
-
可進行按需載入...
相關推薦
利用pushState, popState和location.hash等方法自己實現一個小型路由
這篇文章主要是記錄下HTML5中history提供的pushState, replaceStateAPI。最後通過這些API自己實現小型的路由。 關於window.history提供的API請參見Mozilla文件 其中history提供的pushState和replace
stub 和 skeleton 的講解,自己實現一個stub和skeleton程式
RMI的本質就是實現在不同JVM之間的呼叫,它的實現方法就是在兩個JVM中各開一個Stub和Skeleton,二者通過socket通訊來實現引數和返回值的傳遞。 有關RMI的例子程式碼網上可以找到不少,但絕大部分都是通過extend the interface java.rmi.Remote實現,
利用iframe和location.hash實現跨域
原理是利用location.hash來進行傳值。在url: http://a.com#helloword中的‘#helloworld’就是location.hash,改變hash並不會導致頁面重新整理,所
關於利用HashSet,split,deleteCharAt等方法詳解
1.首先了解一下HashSet的原理: Set介面 Set是對數學上集的抽象,Set中不包含重複的元素.如何界定是否是重複元素?Set最多可含一個null元素;對於任意的非null元素e1和e2,都滿足e1.equals(e2)==false. Object.hashcode()的約定:a.在程式的一次執
使用javascript和jquery兩種方法,實現密碼明文和密文的轉換
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>&
jQuery中利用keyup事件和判斷是否為漢字來實現動態搜尋
需求:有時候在做介面搜尋功能的時候,會想要根據使用者輸入的漢字來檢索出相應的內容。要求是動態的檢索,使用者每次輸入一個字或一個詞就會進行關鍵字模糊搜尋。 實現方法:如果直接使用文字框的keyup()事
Java用類和物件,構造方法來實現超市管理系統
1.用自己的思維模式構建了2個類(User類和Account類)來實現。 2.根據馮經理的思維多建立了幾個方法(login(),initDate(),search(),delete(),),發現把很多功能模組寫成方法會使程式可讀性更強 • 遇到的問題和解決方案; 問題:
java中有幾種方法可以實現一個執行緒?用什麼關鍵字修飾同步方法 stop()和suspend()方法為何不推薦使用?
java5以前,有兩種實現方法,分別使用new Thread()和new Thread(runnable)形式,第一種繼承Thread類,直接呼叫thread的run方法,所以,我們往往使用Thread子類,即new SubThread()。第二種是實現Runn
歸併排序--自上而下和自下而上兩種方法的實現
歸併排序思想 自上而下的遞迴 對一個數組(str)選中一箇中間位置(mid=(start+end)/2),分別進行左遞迴(mergeSort(str,start,mid,length)),右遞迴(mergeSort(str,mid+1,end,length)),在回朔的時候
java中有幾種方法可以實現一個執行緒?用什麼關鍵字修飾同步方法? stop()和suspend()方法為何不推薦使用?
java5以前,有如下兩種: 第一種: new Thread(){}.start();這表示呼叫Thread子類物件的run方法,new Thread(){}表示一個Thread的匿名子類的例項物件,子類加上run方法後的程式碼如下: new Thread(){ publi
不使用JDK的方法自己實現字符串轉整數
for parse 使用 har trim ++ exception int char 暫未考慮正負符號的情況。 public static int parseInt(String str) { if (str == null || str.tri
python只使用Queue和Thread自己實現一個最簡單的執行緒池
我的思路就是就是寫一個TifCutting類繼承自Thread,這個類裡有個屬性Queue;有一個addTask新增任務的方法,這個方法是把需要執行的函式放到Queue裡;因為繼承自Thread類,一定有一個重寫的run方法,這個方法是從自己的Queue屬性裡
利用HashMap,自己實現一個簡易版的HashSet
簡介 HashSet是常用的容器類,主要特徵表現為不可重複性 其內部實現主要用到了HashMap,利用了HashMap的鍵的不可重複性 使用HashMap的鍵作為其元素,同時令HashMap的所有的
講解tf.estimator.Estimator tf.layers等高階API實現一個CNN
tf.contrib.layers.flatten 假設輸入(inputs)的第一個維度表示batch_size。在保持batch_size的同時,使輸入的shape變為: [batch_size, k] tf.contrib.layers.flatten( inputs,
Quartz 之 scheduler 類的方法 【實現一個 quartz 管理類】
pause : 暫停一個觸發器。如果是持久化的 quartz,此觸發器的狀態會被寫到庫中,哪怕是重啟應用後, 也不會觸發,因為狀態是持久化的。 若更新 quartz 配置檔案中的該觸發器的屬性,如 cron 表示式,則記憶體和資料庫中已持久化的資料都不會被更新。 res
netty原始碼解解析(4.0)-20 ChannelHandler: 自己實現一個自定義協議的伺服器和客戶端
本章不會直接分析Netty原始碼,而是通過使用Netty的能力實現一個自定義協議的伺服器和客戶端。通過這樣的實踐,可以更深刻地理解Netty的相關程式碼,同時可以瞭解,在設計實現自定義協議的過程中需要解決的一些關鍵問題。 本週章涉及到的程式碼可以從github上下載: https://git
div+css 兼容ie6 ie7 ie8 ie9和FireFox Chrome等瀏覽器方法(非原創)
需要 通過 是我 point 一定的 oba 對象 important not div+css 兼容ie6 ie7 ie8 ie9和FireFox Chrome等瀏覽器方法 1.DOCTYPE 影響 CSS 處理 2.FF: div 設置 margi
Python: 字符串搜索和匹配,re.compile() 編譯正則表達式字符串,然後使用match() , findall() 或者finditer() 等方法
nth post cde clas import 預編譯 正則 一次 find 1. 使用find()方法 >>> text = ‘yeah, but no, but yeah, but no, but yeah‘ >>> text.fi
Django通用檢視的get_queryset, get_context_data和get_object等方法
Django通用檢視的get_queryset, get_context_data和get_object等方法 簡介: Django提供了很多通用的基於類的檢視(class Base View),可以幫我簡化以下的程式碼操作。 這些基類的檢視還提供了get_queryset()
putty等終端遠端登入Ubuntu 'ls'命令沒有顏色的解決方法(附 ll和la命令解決方法)
今天在一臺新的電腦上下載了putty工具遠端登入了下Ubuntu伺服器,執行了 ‘ls’ 命令,竟然列出的檔案或目錄都同一顏色,體驗相當不好: 解決方法,只要修改下~/.bash_profile檔案就可以了,在檔案中新增命令:alias ls=’ls --colo