詳解vue的hash跳轉(zhuǎn)原理
在new vueRouter的時候我們可以傳入一個mode屬性,他可以接收三個值:hash/history/abstract

hash和history的區(qū)別
history的路徑更美觀一點 比如http://yoursite.com/user/id,history是基于pushState()來完成 URL 跳轉(zhuǎn)而無須重新加載頁面。 但是強制刷新還是會有問題(服務(wù)端來解決這個問題),所以history模式需要后端人員配合使用。
hash的路徑會帶有#,比如http://yoursite.com#/user/id
HashHistory
class VueRouter{
constructor(options){
this.matcher = createMatcher(options.routes || []);
//這里為了講解hash模式 所以就不進行判斷用戶傳進來的是哪種模式了
this.history = new HashHistory(this);//this vue-router的實例
}
}
源碼這里創(chuàng)建了一個基類我們這里和源碼統(tǒng)一,這個基類封裝了三種模式公用的方法和屬性,那么我們在這里創(chuàng)建一個HashHistory和基類History
import History from './base'
// hash路由
export default class HashHistory extends History{
constructor(router){
super(router); //繼承調(diào)用父類 等于call
}
}
// 路由的基類
export default class History {
constructor(router){
this.router = router;
}
}
如果是hash路由,打開網(wǎng)站如果沒有hash默認(rèn)應(yīng)該添加#/
import History from './base';
function ensureSlash(){
if(window.location.hash){
return
}
window.location.hash = '/'
}
export default class HashHistory extends History{
constructor(router){
super(router);
ensureSlash(); // 確保有hash
}
}
再看一下初始化的邏輯(上面的router.init函數(shù))
init(app){
const history = this.history;
// 初始化時,應(yīng)該先拿到當(dāng)前路徑,進行匹配邏輯
// 讓路由系統(tǒng)過度到某個路徑
const setupHashListener = ()=> {
history.setupListener(); // 監(jiān)聽路徑變化
}
history.transitionTo( // 父類提供方法負(fù)責(zé)跳轉(zhuǎn)
history.getCurrentLocation(), // 子類獲取對應(yīng)的路徑
// 跳轉(zhuǎn)成功后注冊路徑監(jiān)聽,為視圖更新做準(zhǔn)備
setupHashListener
)
}
這里我們要分別實現(xiàn) transitionTo(基類方法)、 getCurrentLocation 、setupListener
getCurrentLocation實現(xiàn)
function getHash(){
return window.location.hash.slice(1);
}
export default class HashHistory extends History{
// ...
getCurrentLocation(){
return getHash();
}
}
setupListener實現(xiàn)
export default class HashHistory extends History{
// ...
setupListener(){
window.addEventListener('hashchange', ()=> {
// 根據(jù)當(dāng)前hash值 過度到對應(yīng)路徑
this.transitionTo(getHash());
})
}
}
TransitionTo實現(xiàn)
export function createRoute(record, location) { // {path:'/',matched:[record,record]}
let res = [];
if (record) { // 如果有記錄
while(record){
res.unshift(record); // 就將當(dāng)前記錄的父親放到前面
record = record.parent
}
}
return {
...location,
matched: res
}
}
export default class History {
constructor(router) {
this.router = router;
// 根據(jù)記錄和路徑返回對象,稍后會用于router-view的匹配
this.current = createRoute(null, {
path: '/'
})
}
// 核心邏輯
transitionTo(location, onComplete) {
// 去匹配路徑
let route = this.router.match(location);
// 相同路徑不必過渡
if(
location === route.path &&
route.matched.length === this.current.matched.length){
return
}
//更新路由并且下面會提到改變根實例上的_route屬性
this.updateRoute(route)
onComplete && onComplete();
}
}
export default class VueRouter{
// ...
//做一個代理
match(location){
return this.matcher.match(location);
}
}
macth方法
function match(location){ // 稍后根據(jù)路徑找到對應(yīng)的記錄
let record = pathMap[location]
if (record) { // 根據(jù)記錄創(chuàng)建對應(yīng)的路由
//參數(shù):/about/a:{path:xx,component...},path:'/about/a'
return createRoute(record,{
path:location
})
}
// 找不到則返回空匹配
return createRoute(null, {
path: location
})
}
我們不難發(fā)現(xiàn)路徑變化時都會更改current屬性,我們可以把current屬性變成響應(yīng)式的,每次current變化刷新視圖即可
在install方法中
install(Vue) {
Vue.mixin({ // 給所有組件的生命周期都增加beforeCreate方法
beforeCreate() {
if (this.$options.router) {
//調(diào)用Vue類中雙向數(shù)據(jù)綁定方法
Vue.util.defineReactive(this,'_route',this._router.history.current);
}
}
});
// $route和$router方法 這兩個方法僅僅是vue中最常見的代理 僅僅是為了更加方便
Object.defineProperty(Vue.prototype,'$route',{ // 每個實例都可以獲取到$route屬性
get(){
return this._routerRoot._route;//上面剛進行雙向數(shù)據(jù)綁定的
}
});
Object.defineProperty(Vue.prototype,'$router',{ // 每個實例都可以獲取router實例
get(){
return this._routerRoot._router;
}
})
}
切換路由每次初始化時都需要調(diào)用更新_route的方法,因為install的時候把_route進行雙向數(shù)據(jù)綁定,剛進來是沒有this._router.history.current的,通過發(fā)布訂閱方式來進行訂閱和更新操作;在init方法中增加監(jiān)聽函數(shù)
history.listen((route) => { // 需要更新_route屬性,出入一個函數(shù)
app._route = route
});
export default class History {
constructor(router) {
// ...
this.cb = null;
}
listen(cb){
this.cb = cb; // 注冊函數(shù)
}
updateRoute(route){
this.current =route;
this.cb && this.cb(route); // 更新current后 更新_route屬性
}
}
以上就是詳解vue的hash跳轉(zhuǎn)原理的詳細(xì)內(nèi)容,更多關(guān)于vue的hash跳轉(zhuǎn)原理的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
elementUI Table組件實現(xiàn)表頭吸頂效果(示例代碼)
文章介紹了如何在vue2.6+和elementUI環(huán)境下實現(xiàn)el-table組件的表頭吸頂效果,通過添加樣式、注冊指令、引入指令并在父元素中避免使用overflow:hidden,可以實現(xiàn)場景下表頭始終可見,本文通過實例代碼介紹的非常詳細(xì),感興趣的朋友一起看看吧2025-01-01
vue把頁面轉(zhuǎn)換成圖片導(dǎo)出方式(html2canvas導(dǎo)出不全問題)
這篇文章主要介紹了vue把頁面轉(zhuǎn)換成圖片導(dǎo)出方式(html2canvas導(dǎo)出不全問題),具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-10-10
Vue+Springboot實現(xiàn)接口簽名的示例代碼
這篇文章主要介紹了Vue+Springboot實現(xiàn)接口簽名的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04
在vue-cli3.0 中使用預(yù)處理器 (Sass/Less/Stylus) 配置全局變量操作
這篇文章主要介紹了在vue-cli3.0 中使用預(yù)處理器 (Sass/Less/Stylus) 配置全局變量操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-08-08
vue2?element?實現(xiàn)表格點擊詳情返回時保留查詢參數(shù)的示例代碼
這篇文章主要介紹了vue2?element?實現(xiàn)表格點擊詳情返回時保留查詢參數(shù)的示例代碼,本文通過圖文示例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-03-03
vue使用拖拽方式創(chuàng)建結(jié)構(gòu)樹
這篇文章主要為大家詳細(xì)介紹了vue使用拖拽方式創(chuàng)建結(jié)構(gòu)樹,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-10-10
vue監(jiān)聽滾動事件實現(xiàn)滾動監(jiān)聽
本文主要介紹了vue監(jiān)聽滾動事件實現(xiàn)滾動監(jiān)聽的相關(guān)資料。具有很好的參考價值。下面跟著小編一起來看下吧2017-04-04

