欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解JavaScript實現(xiàn)監(jiān)聽路由變化

 更新時間:2021年08月16日 10:48:21   作者:Branlen  
前端實現(xiàn)路由變化主要有兩種方式,本文主要介紹了這兩種方法的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下

前端實現(xiàn)路由變化主要有兩種方式,這兩種方式最大特點就是實現(xiàn)URL切換無刷新功能

  1. 通過hash改變,利用window.onhashchange 監(jiān)聽。
  2. 通過history的改變,進(jìn)行js操作加載頁面,然而history并不像hash那樣簡單,因為history的改變,除了瀏覽器的幾個前進(jìn)后退(使用 history.back(), history.forward()和 history.go() 方法來完成在用戶歷史記錄中向后和向前的跳轉(zhuǎn)。)等操作會主動觸發(fā)popstate 事件,pushState,replaceState 并不會觸發(fā)popstate事件。

history

主要來了解一下History

pushState()方法

需要三個參數(shù): 一個狀態(tài)對象, 一個標(biāo)題 (目前被忽略), 和 (可選的) 一個URL. 讓我們來解釋下這三個參數(shù)詳細(xì)內(nèi)容:

狀態(tài)對象(state object) — 狀態(tài)對象state是一個JavaScript對象,通過pushState () 創(chuàng)建新的歷史記錄條目。無論什么時候用戶導(dǎo)航到新的狀態(tài),popstate事件就會被觸發(fā),且該事件的state屬性包含該歷史記錄條目狀態(tài)對象的副本。 狀態(tài)對象可以是能被序列化的任何東西。原因在于Firefox將狀態(tài)對象保存在用戶的磁盤上,以便在用戶重啟瀏覽器時使用,我們規(guī)定了狀態(tài)對象在序列化表示后有640k的大小限制。如果你給 pushState() 方法傳了一個序列化后大于640k的狀態(tài)對象,該方法會拋出異常。如果你需要更大的空間,建議使用 sessionStorage 以及 localStorage.

標(biāo)題(title) — Firefox 目前忽略這個參數(shù),但未來可能會用到。在此處傳一個空字符串應(yīng)該可以安全的防范未來這個方法的更改。或者,你可以為跳轉(zhuǎn)的state傳遞一個短標(biāo)題。

URL — 該參數(shù)定義了新的歷史URL記錄。注意,調(diào)用pushState() 后瀏覽器并不會立即加載這個URL,但可能會在稍后某些情況下加載這個URL(不會加載該資源,但我們可以通過監(jiān)聽它的改變,來改變視圖,這就成為單頁面的路由實現(xiàn)的一個方式,實現(xiàn)頁面無刷新),比如在用戶重新打開瀏覽器時。新URL不必須為絕對路徑。如果新URL是相對路徑,那么它將被作為相對于當(dāng)前URL處理。新URL必須與當(dāng)前URL同源(同源策略),否則 pushState()會拋出一個異常。該參數(shù)是可選的,缺省為當(dāng)前URL。

在某種意義上,調(diào)用 pushState() 與 設(shè)置 window.location = “#foo” 類似,二者都會在當(dāng)前頁面創(chuàng)建并激活新的歷史記錄。但 pushState()具有如下幾條優(yōu)點:

新的 URL可以是與當(dāng)前URL同源的任意URL 。相反,只有在修改哈希時,設(shè)置 window.location 才能是同一個 document。
如果你不想改URL,就不用改。相反,設(shè)置 window.location = “#foo”;在當(dāng)前哈希不是 #foo 時, 才能創(chuàng)建新的歷史記錄項。
你可以將任意數(shù)據(jù)和新的歷史記錄項相關(guān)聯(lián)。而基于哈希的方式,要把所有相關(guān)數(shù)據(jù)編碼為短字符串。
如果 標(biāo)題 隨后還會被瀏覽器所用到,那么這個數(shù)據(jù)是可以被使用的(哈希則不是)。

注意pushState() 絕對不會觸發(fā) hashchange 事件,即使新的URL與舊的URL僅哈希不同也是不會觸發(fā)。

pushState()使用場景

history可實現(xiàn)無刷新修改URL或URL參數(shù)

window.history.replaceState('', '', `${window.location.origin}${window.location.pathname}type=a`);

replaceState() 方法

history.replaceState() 的使用與 history.pushState() 非常相似,區(qū)別在于 replaceState() 是修改了當(dāng)前的歷史記錄項而不是新建一個。 注意這并不會阻止其在全局瀏覽器歷史記錄中創(chuàng)建一個新的歷史記錄項。
使

popstate事件

使用 window.onpopstate來監(jiān)聽返回事件

window.onpopstate = funcRef;

funcRef : (Event:{state:any})=>void

每當(dāng)處于激活狀態(tài)的歷史記錄發(fā)生改變時,popstate事件就會被觸發(fā),在對應(yīng)的window的對象上觸發(fā)(window.onpopstate)。如果當(dāng)前處于激活狀態(tài)的歷史記錄條目是由history.pushState()方法創(chuàng)建,或者由history.replaceState()方法修改過的, 則popstate事件對象的state屬性包含了這個歷史記錄條目的state對象的一個拷貝.

**注意:

  1. 調(diào)用history.pushState()或者h(yuǎn)istory.replaceState()不會觸發(fā)popstate事件. popstate事件只會在瀏覽器某些行為下觸發(fā), 比如點擊后退、前進(jìn)按鈕(或者在JavaScript中調(diào)用history.back()、history.forward()、history.go()方法),此外,a 標(biāo)簽的錨點也會觸發(fā)該事件.
  2. 當(dāng)網(wǎng)頁加載時,各瀏覽器對popstate事件是否觸發(fā)有不同的表現(xiàn),Chrome 和 Safari會觸發(fā)popstate事件, 而Firefox不會.

pushState和replaceState如何監(jiān)聽呢?

我們可以自己通過訂閱-發(fā)布模式進(jìn)行實現(xiàn):首先使用Dep和Watch,訂閱和發(fā)布模式,其實是參考vue源碼 dep和wantcher之間實現(xiàn)方式的簡易版

class Dep {                  // 訂閱池
    constructor(name){
        this.id = new Date() //這里簡單的運用時間戳做訂閱池的ID
        this.subs = []       //該事件下被訂閱對象的集合
    }
    defined(){              // 添加訂閱者
        Dep.watch.add(this);
    }
    notify() {              //通知訂閱者有變化
        this.subs.forEach((e, i) => {
            if(typeof e.update === 'function'){
                try {
                   e.update.apply(e)  //觸發(fā)訂閱者更新函數(shù)
                } catch(err){
                    console.warr(err)
                }
            }
        })
    }
    
}
Dep.watch = null;

class Watch {
    constructor(name, fn){
        this.name = name;       //訂閱消息的名稱
        this.id = new Date();   //這里簡單的運用時間戳做訂閱者的ID
        this.callBack = fn;     //訂閱消息發(fā)送改變時->訂閱者執(zhí)行的回調(diào)函數(shù)     
    }
    add(dep) {                  //將訂閱者放入dep訂閱池
       dep.subs.push(this);
    }
    update() {                  //將訂閱者更新方法
        var cb = this.callBack; //賦值為了不改變函數(shù)內(nèi)調(diào)用的this
        cb(this.name);          
    }
}     

重新history方法,并添加addHistoryListener方法

const addHistoryMethod= (function(){
 var historyDep = new Dep()// 創(chuàng)建訂閱池
 return function (name){
  if(name==='historyChange'){
   var event = new Watch(name,fn);
   Dep.watch = evnet;
   historyDep.defind();//增加訂閱者
   Dep.watch = null;
  }else if(name==='pushState'||name==='replaceState'){
   var method = history[name];
   return function(){
    method.apply(history,argumnets)
    historyDep.notify();
   }
  }
 }
})()
window.addHistoryListener = addHistoryMethod('historyChange')
history.pushState =  addHistoryMethod('pushState');
history.replaceState =  addHistoryMethod('replaceState');

封裝成功,測試使用例子

window.addHistoryListener('history',function(){
 console.log('窗口history改變了')
})
window.addHistoryListerer('history',function(){
 console.log('窗口history改變,我也聽到了')// 可綁定多個監(jiān)聽事件
 console.log(history.state)
})
history.pushState({foo:bar}, 'title', '/car')

獲取當(dāng)前狀態(tài)

頁面加載時,或許會有個非null的狀態(tài)對象。這是有可能發(fā)生的,舉個例子,假如頁面(通過pushState() 或 replaceState() 方法)設(shè)置了狀態(tài)對象而后用戶重啟了瀏覽器。那么當(dāng)頁面重新加載時,頁面會接收一個onload事件,但沒有popstate 事件。然而,假如你讀取了history.state屬性,你將會得到如同popstate 被觸發(fā)時能得到的狀態(tài)對象。

你可以讀取當(dāng)前歷史記錄項的狀態(tài)對象state,而不必等待popstate 事件, 只需要這樣使用history.state屬性:

let currentState = history.state;

對比

pushState replaceState
會在當(dāng)前頁面創(chuàng)建并激活新的歷史記錄,點擊返回按鈕會返回到之前的url 會修改當(dāng)前的歷史記錄,按回退按鈕,會跳過被修改的url

總結(jié)

history是實現(xiàn)無刷新路由的一種方式,特別適合我們進(jìn)行單頁面的開發(fā),保證系統(tǒng)穩(wěn)定的體驗性,但是history不監(jiān)聽pushState和replaceState的行為,只是監(jiān)聽go、back、forward行為。但我們可以使用訂閱發(fā)布模式,使用Dep和Watch,對pushState和replaceState事件進(jìn)行重新封裝,調(diào)用后會自動觸發(fā)notify方法,增加一個addHistoryListener的方法,用來增加監(jiān)聽回調(diào)(訂閱者)。

到此這篇關(guān)于詳解JavaScript實現(xiàn)監(jiān)聽路由變化的文章就介紹到這了,更多相關(guān)JavaScript監(jiān)聽路由變化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論