最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解JavaScript實(shí)現(xiàn)監(jiān)聽(tīng)路由變化

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

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

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

history

主要來(lái)了解一下History

pushState()方法

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

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

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

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

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

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

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

pushState()使用場(chǎng)景

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

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

replaceState() 方法

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

popstate事件

使用 window.onpopstate來(lái)監(jiān)聽(tīng)返回事件

window.onpopstate = funcRef;

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

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

**注意:

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

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

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

class Dep {                  // 訂閱池
    constructor(name){
        this.id = new Date() //這里簡(jiǎn)單的運(yùn)用時(shí)間戳做訂閱池的ID
        this.subs = []       //該事件下被訂閱對(duì)象的集合
    }
    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();   //這里簡(jiǎn)單的運(yùn)用時(shí)間戳做訂閱者的ID
        this.callBack = fn;     //訂閱消息發(fā)送改變時(shí)->訂閱者執(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');

封裝成功,測(cè)試使用例子

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

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

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

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

let currentState = history.state;

對(duì)比

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

總結(jié)

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

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

相關(guān)文章

最新評(píng)論

大化| 大英县| 霞浦县| 遂宁市| 九江县| 亚东县| 长海县| 高碑店市| 苍南县| 平顶山市| 隆子县| 商洛市| 太保市| 西城区| 元谋县| 勐海县| 江油市| 泰安市| 台安县| 花莲市| 牟定县| 盘山县| 库车县| 远安县| 虎林市| 师宗县| 定南县| 右玉县| 绥阳县| 揭阳市| 五原县| 洪江市| 班玛县| 高安市| 平昌县| 宁都县| 阿坝县| 米泉市| 祁门县| 镇安县| 巴林右旗|