VueRouter路由模式全面解析
VueRouter路由模式
前端路由的實(shí)現(xiàn)方式主要有兩種:hash
模式和history
模式。
hash模式
在window.location
對象中有一個hash
字段,可以獲取地址欄中#
字符及后邊的所有字符。
hash
也稱作錨點(diǎn),本身是用來做頁面定位的,可以使對應(yīng)id
的元素顯示在可是區(qū)域內(nèi)。
比如說下面這張動圖,通過錨點(diǎn)直接跳轉(zhuǎn)到footer
:
hash
雖然出現(xiàn)在 URL
中,但不會被包括在 HTTP
請求中,不會對請求有影響。
下圖可以看到雖然地址是http://localhost:3000/index.html#footer
,但是network
中的請求是http://localhost:3000/index.html
。
由于hash
值變化不會導(dǎo)致瀏覽器向服務(wù)器發(fā)出請求,而且hash
改變會觸發(fā)hashchange
事件,瀏覽器的進(jìn)后退也能對其進(jìn)行控制,所以在 html5
的 history
出現(xiàn)前,開發(fā)者基本都是使用 hash
來實(shí)現(xiàn)前端路由的。
history模式
HTML5
規(guī)范提供了history.pushState
和history.replaceState
來進(jìn)行路由控制。
通過這兩個方法可以改變url
且不向服務(wù)器發(fā)送請求。
同時不會像hash
有一個#
,更加的美觀。
但是如果刷新頁面,那么請求的資源就是當(dāng)前地址欄中的地址了,對于SPA
應(yīng)用來說就需要進(jìn)行配置將所有的路由重定向到根頁面。
調(diào)用pushState
跳轉(zhuǎn)到相同的路由時仍可以成功且路由棧數(shù)量會加1。
這個可以重寫pushState
方法來進(jìn)行過濾。
const stack = []; const originPushState = window.history.pushState; window.history.pushState = function() { if(stack[stack.length - 1] === arguments[2]) { return; } stack.push(arguments[2]) originPushState.call(history, ...arguments); }
history.replaceState
和 history.pushState
卻不會觸發(fā) popstate
事件,不過可以手動創(chuàng)建一個PopStateEvent
并觸發(fā)該事件。
function createPopStateEvent(state, title) { return new PopStateEvent("popstate", { state: state, title: title }); } window.history.pushState = function() { if(stack[stack.length - 1] === arguments[2]) { return; } stack.push(arguments[2]) window.dispatchEvent(createPopStateEvent(...arguments)); originPushState.call(history, ...arguments); }
VueRouter中的路由模式
文章中介紹的vue-router
源碼版本為v3.4.9
。
hash模式
在hash
模式中,VueRouter
主要還是以history.pushState
為首選,在不支持history
的瀏覽器中才會通過改變location.hash
的值來實(shí)現(xiàn)路由切換。
在源碼中的hash.js
文件中的pushHash
方法明確定義。
// src/history/hash.js function pushHash (path) { if (supportsPushState) { pushState(getUrl(path)) } else { window.location.hash = path } }
同時在beforeCreate
監(jiān)聽hashchange
方法,防止用戶直接在地址欄上修改url
。
通過點(diǎn)擊跳轉(zhuǎn)的方式VueRouter
做了處理并不會觸發(fā)該方法。
const eventType = supportsPushState ? 'popstate' : 'hashchange' window.addEventListener( eventType, handleRoutingEvent )
hash
模式為什么首先考慮使用history.pushState
呢?
因?yàn)橥ㄟ^history.pushState
可以設(shè)置state
值,VueRouter
在每個路由跳轉(zhuǎn)時帶有唯一的key
,可以用于在瀏覽器后退前進(jìn)時恢復(fù)到之前的滾動的位置。
在源碼中的pushState
方法中可以看到,在跳轉(zhuǎn)前保存當(dāng)前路由的滾動條位置,同時為跳轉(zhuǎn)路由添加一個新key
標(biāo)識新路由。
function pushState (url?: string, replace?: boolean) { saveScrollPosition() const history = window.history // safari存在問題,路由棧中只能保存100,超過100個異常捕獲用location來替換路由對象 try { if (replace) { const stateCopy = extend({}, history.state) stateCopy.key = getStateKey() history.replaceState(stateCopy, '', url) } else { history.pushState({ key: setStateKey(genStateKey()) }, '', url) } } catch (e) { window.location[replace ? 'replace' : 'assign'](url) } }
history模式
在初始化history
模式時,監(jiān)聽popstate
,在路由變化時恢復(fù)滾動條位置。
// src/history/html5.js this.transitionTo(location, (route) => { if (supportsScroll) { handleScroll(router, route, current, true) } }) window.addEventListener('popstate', handleRoutingEvent)
前面提到history.pushState
和history.replaceState
兩個方法不會觸發(fā)popstate
方法,因此在push
和replace
方法中,在路由切換成功后手動執(zhí)行hashScroll
方法。
// src/history/html5.js push(location: RawLocation, onComplete?: Function, onAbort?: Function) { const { current: fromRoute } = this this.transitionTo( location, (route) => { pushState(cleanPath(this.base + route.fullPath)) handleScroll(this.router, route, fromRoute, false) onComplete && onComplete(route) }, onAbort ) }
abstract模式
在VueRouter
中除了hash
和history
兩種模式外,還新增了一個abstract
模式,用來在不支持瀏覽器的環(huán)境中充當(dāng)一個備用方案(例如Weex
)。
在abstract
模式中新建了一個對象用來模擬瀏覽器中路由棧。
this.stack = []
同時提供了三個路由跳轉(zhuǎn)方法push
、replace
和go
,這三種方法跟hash
和history
模式中的push
、replace
和go
方法類似,來看看是怎么實(shí)現(xiàn)的。
// src/history/abstract.js push()方法 route => { // 在路由棧中添加一個新路由 this.stack = this.stack.slice(0, this.index + 1).concat(route) this.index++ onComplete && onComplete(route) }
因?yàn)榉菫g覽器環(huán)境中沒有前進(jìn)后退按鈕,因此replace
其實(shí)就是替換掉路由棧中的最后一個路由。
// src/history/abstract.js replace()方法 route => { // 在路由棧中替換掉最后一個路由 this.stack = this.stack.slice(0, this.index).concat(route) this.index++ onComplete && onComplete(route) }
在go
方法中同樣對傳入的數(shù)字進(jìn)行判斷是否在路由棧的范圍內(nèi),否則不執(zhí)行。
// src/history/abstract.js go()方法 const targetIndex = this.index + n if (targetIndex < 0 || targetIndex >= this.stack.length) { return }
之后直接將路由索引指向需要跳轉(zhuǎn)的路由索引同時更新當(dāng)前路由。
// src/history/abstract.js go()方法 const route = this.stack[targetIndex] this.confirmTransition( route, () => { this.index = targetIndex this.updateRoute(route) // ... ) // src/history/base.js updateRoute(route: Route) { this.current = route this.cb && this.cb(route) }
無論是hash
還是history
模式都需要對瀏覽器當(dāng)前的URL
產(chǎn)生影響,通過與abstract
結(jié)合也可以實(shí)現(xiàn)在已存在的路由頁面中內(nèi)嵌其他的路由頁面,而保持在瀏覽器當(dāng)中依舊顯示當(dāng)前頁面的路由path
。
比如定義了一個hash
模式并存在兩個路由的實(shí)例掛載在app
上,其中第二個路由中又定義一個abstract
模式的路由。這時候切換/route1
和/route2
并不會影響URL
。
const routes = [ { path: '/', component: { template: `<div>default view</div>` } }, { path: '/abstractRoute', component: { name: "abstract", template: '<div><h1 @click="toRoute(1)">跳轉(zhuǎn)到router1</h1><h1 @click="toRoute(2)">跳轉(zhuǎn)到router2</h1><router-view></router-view></div>', methods: { toRoute(num) { this.$router.push(`/route${num}`); } }, router: new VueRouter({ routes: [ { path: '/route1', component: {template:'<h1>abstract route 1</h1>'} }, { path: '/route2', component: { template:'<h1>abstract route 2</h1>'} }, ], mode: 'abstract' }) } }, ] const app = new Vue({ router: new VueRouter({ routes, mode: 'hash' }), template: `<div><router-link to="/">to /</router-link> <router-link to="/abstractRoute">to abstractRoute</router-link> <router-view></router-view> </div>`, }).$mount('#app')
總結(jié)
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Vue.js中vue-property-decorator的使用方法詳解
vue-property-decorator是一個用于在Vue.js中使用TypeScript裝飾器的庫,它能夠簡化 Vue 組件的定義,使代碼更加簡潔和可維護(hù),它能夠簡化Vue組件的定義,使代碼更加簡潔和可維護(hù),本文將深入探討vue-property-decorator的使用方法,并展示如何在Vue.js項(xiàng)目中應(yīng)用它2024-08-08Vue3?企業(yè)級組件庫框架搭建?pnpm?monorepo實(shí)戰(zhàn)示例
這篇文章主要為大家介紹了Vue3?企業(yè)級組件庫框架搭建?pnpm?monorepo實(shí)戰(zhàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11Vue2.0用 watch 觀察 prop 變化(不觸發(fā))
本篇文章主要介紹了Vue2.0用 watch 觀察 prop 變化(不觸發(fā)),非常具有實(shí)用價值,需要的朋友可以參考下2017-09-09