成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

history和hash,vue-router

godiscoder / 1677人閱讀

摘要:另外該事件只針對同一個文檔,如果瀏覽歷史的切換,導(dǎo)致加載不同的文檔,該事件不會被觸發(fā)使用的時候,可以為事件指定回調(diào)函數(shù)或者回調(diào)函數(shù)的參數(shù)是一個事件對象,它的屬性指向和方法為當(dāng)前所提供的狀態(tài)對象即這兩個方法的第一個參數(shù)。

history

window.history(可直接寫成history)指向History對象,它表示當(dāng)前窗口的瀏覽歷史。History對象保存了當(dāng)前窗口訪問過的所有頁面網(wǎng)址

history對象的常見屬性和方法
go()
接受一個整數(shù)為參數(shù),移動到該整數(shù)指定的頁面,比如history.go(1)相當(dāng)于history.forward(),history.go(-1)相當(dāng)于history.back(),history.go(0)相當(dāng)于刷新當(dāng)前頁面
back()
移動到上一個訪問頁面,等同于瀏覽器的后退鍵,常見的返回上一頁就可以用back(),是從瀏覽器緩存中加載,而不是重新要求服務(wù)器發(fā)送新的網(wǎng)頁
forward()
移動到下一個訪問頁面,等同于瀏覽器的前進(jìn)鍵
pushState()
在瀏覽器歷史中添加記錄,方法接受三個參數(shù),以此為:

history.pushstate(state,title,url)

if(!!(window.hostory && history.pushState)) {
// 支持History API
} else {
    // 不支持
}

state: 一個與指定網(wǎng)址相關(guān)的狀態(tài)對象,popState事件觸發(fā)時,該對象會傳入回調(diào)函數(shù),如果不需要這個對象,此處可填null
title: 新頁面的標(biāo)題,但是所有瀏覽器目前都忽略這個值,因此這里可以填null
url: 新的網(wǎng)址,必須與當(dāng)前頁面處在同一個域,瀏覽器的地址欄將顯示這個網(wǎng)址

history.pushState({a:1},"page 2","2.html")

用上面代碼添加2.html后,瀏覽器地址欄立刻顯示2.html,但不會跳到2.html,只會更新瀏覽器歷史記錄,此時點擊后退按鈕則會回到原網(wǎng)頁,但是會改變history的length屬性;
如果pushState的url參數(shù),設(shè)置了一個新的錨點值(即hash),并不會觸發(fā)hashChange事件,如果設(shè)置了一個跨域網(wǎng)址,則會報錯。

replaceState()
history.replaceState()方法的參數(shù)和pushState()方法一摸一樣,區(qū)別是它修改瀏覽器歷史當(dāng)中的記錄
兩者的區(qū)別在于
push
此時執(zhí)行history.back()返回/about

replace
此時執(zhí)行history.back()返回/blog

length
history.length屬性保存著歷史記錄的url數(shù)量,初始時該值為1,如果當(dāng)前窗口先后訪問了三個網(wǎng)址,那么history對象就包括3項,history.length=3
state
返回當(dāng)前頁面的state對象??梢酝ㄟ^replaceState()和pushState()改變state,可以存儲很多數(shù)據(jù)
scrollRestoration
history.scrollRestoration = "manual";關(guān)閉瀏覽器自動滾動行為
history.scrollRestoration = "auto";打開瀏覽器自動滾動行為(默認(rèn))
popState 事件
每當(dāng)同一個文檔的瀏覽歷史(即history)出現(xiàn)變化時,就會觸發(fā)popState事件
需要注意:僅僅調(diào)用pushState方法或replaceState方法,并不會觸發(fā)該事件,只有用戶點擊瀏覽器后退和前進(jìn)按鈕時,或者使用js調(diào)用back、forward、go方法時才會觸發(fā)。另外該事件只針對同一個文檔,如果瀏覽歷史的切換,導(dǎo)致加載不同的文檔,該事件不會被觸發(fā)
使用的時候,可以為popState事件指定回調(diào)函數(shù)

window.onpopstate = function (event) {
      console.log("location: " + document.location);
      console.log("state: " +JSON.stringify(event.state));
    };
    
    // 或者
    
    window.addEventListener("popstate", function(event) {
      console.log("location: " + document.location);
      console.log("state: " + JSON.stringify(event.state));
    });

回調(diào)函數(shù)的參數(shù)是一個event事件對象,它的state屬性指向pushState和replaceState方法為當(dāng)前url所提供的狀態(tài)對象(即這兩個方法的第一個參數(shù))。上邊代碼中的event.state就是通過pushState和replaceState方法為當(dāng)前url綁定的state對象
這個state也可以直接通過history對象讀取
history.state
注意:頁面第一次加載的時候,瀏覽器不會觸發(fā)popState事件

hash

hash 就是指 url 尾巴后的 # 號以及后面的字符。這里的 # 和 css 里的 # 是一個意思。hash 也 稱作 錨點,本身是用來做頁面定位的,她可以使對應(yīng) id 的元素顯示在可視區(qū)域內(nèi)。

通過window.location.hash獲取hash值

延伸:
window.location對象里面
hash : 設(shè)置或返回從 (#) 開始的 URL(錨)。
host : 設(shè)置或返回主機名和當(dāng)前 URL 的端口號。
hostname:設(shè)置或返回當(dāng)前 URL 的主機名。
href : 設(shè)置或返回完整的 URL。
pathname: 設(shè)置或返回當(dāng)前 URL 的路徑部分。
port:設(shè)置或返回當(dāng)前 URL 的端口號。
search : 設(shè)置或返回從問號 (?) 開始的 URL(查詢部分)。
assign() : 加載新的文檔。
reload() : 重新加載當(dāng)前文檔。
replace() : 用新的文檔替換當(dāng)前文檔。
hashchange

當(dāng)hash值改變時會觸發(fā)這個事件,
if("onhashchange" in window) {
   window.addEventListener("hashchange",function(e){
    console.log(e.newURL,e.oldURL)
},false)
}
vue-router

在vue-router中,它提供mode參數(shù)來決定采用哪一種方式;
默認(rèn)是hash,可以配置mode:history,選擇history模式;
選好mode后 vueRouter中會創(chuàng)建history對象(HashHistory或HTML5History,這兩種類都是繼承History類,這個類定義了一些公共方法)

// 根據(jù)mode確定history實際的類并實例化
    switch (mode) {
      case "history":
        this.history = new HTML5History(this, options.base)
        break
      case "hash":
        this.history = new HashHistory(this, options.base, this.fallback)
        break
      case "abstract":
        this.history = new AbstractHistory(this, options.base)
        break
      default:
        if (process.env.NODE_ENV !== "production") {
          assert(false, `invalid mode: ${mode}`)
        }
    }
  }

現(xiàn)在我們來看當(dāng)我們在代碼中執(zhí)行了this.$router.push()之后具體的流程

首先看HashHistory
1 $router.push() //顯式調(diào)用方法
2 HashHistory.push() // 我們來看下push方法

push (location: RawLocation, onComplete?: Function, onAbort?: Function) {
  this.transitionTo(location, route => {
    pushHash(route.fullPath)
    onComplete && onComplete(route)
  }, onAbort)
}

function pushHash (path) {
  window.location.hash = path
}

transitionTo()方法是父類中定義的是用來處理路由變化中的基礎(chǔ)邏輯的,push()方法最主要的是對window的hash進(jìn)行了直接賦值:hash的改變會自動添加到瀏覽器的訪問歷史記錄中。

window.location.hash = route.fullPath //類似/thunder/bless_sort/1?fromType=homeTap

那么視圖的更新是怎么實現(xiàn)的呢,我們來看父類History中transitionTo()方法的這么一段:

transitionTo (location: RawLocation, onComplete?: Function, onAbort?: Function) {
  const route = this.router.match(location, this.current)
  this.confirmTransition(route, () => {
    this.updateRoute(route)
    ...
  })
}

updateRoute (route: Route) {
  
  this.cb && this.cb(route)
  
}

listen (cb: Function) {
  this.cb = cb
}

路由變化后會執(zhí)行updateRoute(),其實是執(zhí)行this.cb ,而 this.cb是在listen函數(shù)中被執(zhí)行的,那么在那里調(diào)用listen函數(shù)呢

init (app: any /* Vue component instance */) {
    
  this.apps.push(app)

  history.listen(route => {
    this.apps.forEach((app) => {
      app._route = route
    })
  })
}

app為vue組件實例,vue本身是沒有vue-routerd的,需要在組件中掛載這個屬性

export function install (Vue) {
  
  Vue.mixin({
    beforeCreate () {
      if (isDef(this.$options.router)) {
        this._router = this.$options.router
        this._router.init(this)
        Vue.util.defineReactive(this, "_route", this._router.history.current)
      }
      registerInstance(this, this)
    },
  })
}

通過Vue.mixin()方法,全局注冊一個混合,影響注冊之后所有創(chuàng)建的每個 Vue 實例,該混合在beforeCreate鉤子中通過Vue.util.defineReactive()定義了響應(yīng)式的_route屬性(當(dāng)前的路由)。即當(dāng)_route值改變時,會自動調(diào)用Vue實例的render()方法,更新視圖。
總結(jié)一下,從設(shè)置路由改變到視圖更新的流程如下:

$router.push() --> HashHistory.push() --> History.transitionTo() --> History.updateRoute() --> {app._route = route} --> vm.render()

replace方法
功能: 替換當(dāng)前路由并更新視圖,常用情況是地址欄直接輸入新地址
流程與push基本一致
但流程2變?yōu)樘鎿Q當(dāng)前hash (window.location.replace= XXX)
replace和hash的區(qū)別在于它并不是將新路由添加到瀏覽器訪問歷史的棧頂,而是替換掉當(dāng)前的路由:如上圖

監(jiān)聽地址欄
以上討論的VueRouter.push()和VueRouter.replace()是可以在vue組件的邏輯代碼中直接調(diào)用的,除此之外在瀏覽器中,用戶還可以直接在瀏覽器地址欄中輸入改變路由,因此VueRouter還需要能監(jiān)聽瀏覽器地址欄中路由的變化,并具有與通過代碼調(diào)用相同的響應(yīng)行為。在HashHistory中這一功能通過setupListeners實現(xiàn):

setupListeners () {
  window.addEventListener("hashchange", () => {
    if (!ensureSlash()) {
      return
    }
    this.transitionTo(getHash(), route => {
      replaceHash(route.fullPath)
    })
  })
}

該方法設(shè)置監(jiān)聽了瀏覽器事件hashchange,調(diào)用的函數(shù)為replaceHash,即在瀏覽器地址欄中直接輸入路由相當(dāng)于代碼調(diào)用了replace()方法

而在HTML5History具體又是怎樣的呢
代碼結(jié)構(gòu)以及更新視圖的邏輯與hash模式基本類似,只不過將對window.location.hash直接進(jìn)行賦值window.location.replace()改為了調(diào)用history.pushState()和history.replaceState()方法。
在HTML5History中添加對修改瀏覽器地址欄URL的監(jiān)聽是直接在構(gòu)造函數(shù)中執(zhí)行的:監(jiān)聽popState事件(地址欄變化觸發(fā)window.onpopstate),調(diào)用repalce方法

 constructor (router: Router, base: ?string) {
      
      window.addEventListener("popstate", e => {
        const current = this.current
        this.transitionTo(getLocation(this.base), route => {
          if (expectScroll) {
            handleScroll(router, route, current, true)
          }
        })
      })
    }

除此之外vue-router還為非瀏覽器環(huán)境準(zhǔn)備了一個abstract模式,其原理為用一個數(shù)組stack模擬出瀏覽器歷史記錄棧的功能。以上是vue-router的核心邏輯;

兩種模式對比
History模式的優(yōu)點:
1.History模式的地址欄更美觀。。。
2.History模式的pushState、replaceState參數(shù)中的新URL可為同源的任意URL(可為不同的html文件),而hash只能是同一文檔
3.History模式的pushState、replaceState參數(shù)中的state可為js對象,能攜帶更多數(shù)據(jù)
4.History模式的pushState、replaceState參數(shù)中的title能攜帶字符串?dāng)?shù)據(jù)(當(dāng)然,部分瀏覽器,例如firefox不支持title,一般title設(shè)為null,不建議使用)
缺點:
不過這種模式需要后端配置,因為我們這個頁面是單頁面應(yīng)用,如果用戶直接訪問http://oursite.com/user/id
后臺沒有正確的配置,則就會返回404,
這個時候需要后臺配置一個能夠覆蓋所有情況的候選資源,如果url匹配不到任何靜態(tài)資源時,則要返回同一個index.html;

注:該篇文章參考了https://zhuanlan.zhihu.com/p/...
轉(zhuǎn)載請注明作者 : crystal 我在桌上刻個早字 謝謝啦

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/104709.html

相關(guān)文章

  • vue-router實現(xiàn)原理

    摘要:我們知道是的核心插件,而當(dāng)前項目一般都是單頁面應(yīng)用,也就是說是應(yīng)用在單頁面應(yīng)用中的。原理是傳統(tǒng)的頁面應(yīng)用,是用一些超鏈接來實現(xiàn)頁面切換和跳轉(zhuǎn)的其實剛才單頁面應(yīng)用跳轉(zhuǎn)原理即實現(xiàn)原理實現(xiàn)原理原理核心就是更新視圖但不重新請求頁面。 近期面試,遇到關(guān)于vue-router實現(xiàn)原理的問題,在查閱了相關(guān)資料后,根據(jù)自己理解,來記錄下。我們知道vue-router是vue的核心插件,而當(dāng)前vue項目...

    vibiu 評論0 收藏0
  • 簡述vue-router實現(xiàn)原理

    摘要:源碼解讀閱讀請關(guān)注下代碼注釋打個廣告哪位大佬教我下怎么排版啊,不會弄菜單二級導(dǎo)航撲通是什么首先,你會從源碼里面引入,然后再傳入?yún)?shù)實例化一個路由對象源碼基礎(chǔ)類源碼不選擇模式會默認(rèn)使用模式非瀏覽器環(huán)境默認(rèn)環(huán)境根據(jù)參數(shù)選擇三種模式的一種根據(jù)版 router源碼解讀 閱讀請關(guān)注下代碼注釋 打個廣告:哪位大佬教我下sf怎么排版啊,不會弄菜單二級導(dǎo)航(撲通.gif) showImg(https:...

    Cristalven 評論0 收藏0
  • 簡述vue-router實現(xiàn)原理

    摘要:源碼解讀閱讀請關(guān)注下代碼注釋打個廣告哪位大佬教我下怎么排版啊,不會弄菜單二級導(dǎo)航撲通是什么首先,你會從源碼里面引入,然后再傳入?yún)?shù)實例化一個路由對象源碼基礎(chǔ)類源碼不選擇模式會默認(rèn)使用模式非瀏覽器環(huán)境默認(rèn)環(huán)境根據(jù)參數(shù)選擇三種模式的一種根據(jù)版 router源碼解讀 閱讀請關(guān)注下代碼注釋 打個廣告:哪位大佬教我下sf怎么排版啊,不會弄菜單二級導(dǎo)航(撲通.gif) showImg(https:...

    Ajian 評論0 收藏0

發(fā)表評論

0條評論

godiscoder

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<