vue-router 源碼分析——2. router-link 組件是如何實現導航的

這是對vue-router 3 版本的源碼分析。
本次分析會按以下方法進行:

  1. 按官網的使用文檔順序,圍繞著某一功能點進行分析。這樣不僅能學習優秀的項目源碼,更能加深對項目的某個功能是如何實現的理解。這個對自己的技能提升,甚至面試時的回答都非常有幫助。
  2. 在圍繞某個功能展開講解時,所有不相干的內容都會暫時去掉,等后續涉及到對應的功能時再加上。這樣最大的好處就是能循序漸進地學習,同時也不會被不相干的內容影響。省略的內容都會在代碼中以…表示。
  3. 每段代碼的開頭都會說明它所在的文件目錄,方便定位和查閱。如果一個函數內容有多個函數引用,這些都會放在同一個代碼塊中進行分析,不同路徑的內容會在其頭部加上所在的文件目錄。

本章講解router中 router-link 組件是如何實現導航的。
另外我的vuex3源碼分析也發布完了,歡迎大家學習:
vuex3 最全面最透徹的源碼分析
還有vue-router的源碼分析:
vue-router 源碼分析——1. 路由匹配
vue-router 源碼分析——2. router-link 組件是如何實現導航的

官網例子

  • 在官網例子中,對做了三個注釋:這是個組件、傳入to屬性,渲染成標簽。
  • 以我們主要分析 router-link 組件如果利用必要的數據來實現導航的。
  • 這里先解釋一下,渲染html頁面的功能,是vue-router調用了vue的render函數,這個是vue的核心功能不做分析。所以這里是分析router是如何定位到對應路由以及做了哪些信息收集和處理的。
<script src="https://unpkg.com/vue@2/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router@3/dist/vue-router.js"></script><div id="app"><h1>Hello App!</h1><p><!-- 使用 router-link 組件來導航. --><!-- 通過傳入 `to` 屬性指定鏈接. --><!-- <router-link> 默認會被渲染成一個 `<a>` 標簽 --><router-link to="/foo">Go to Foo</router-link><router-link to="/bar">Go to Bar</router-link></p>
</div>

Vue實例掛載link組件,從而可以使用標簽

  • 這里的install.js實際上是一個VUE的插件,這樣當創建和掛載根實例時自動導入了插件。
  • 這里面還涉及到VUE的混入(Vue.mixin),實現了在任意組件內通過this.$ router和this.$route來訪問路由器和當前路由。感興趣的小伙伴可以去看VUE官網的解釋。
// ./install.js
import Link from './components/link'export function install(Vue) {Vue.component('RouterLink', Link)
}

link.js源碼內容

  • 傳入了一個to變量,對應’/foo’,tag默認為’a’,即標簽.
  • render函數是vue用來描述如果構建虛擬DOM的,即如何按某個定義來構建組件。
  • 如何渲染為html是vue中的核心內容,這里不做討論,只分析vue-router中的源碼內容,即resolve方法。
const { location, route, href } = router.resolve(this.to,current,this.append        )   ...const classes = {}const data: any = { class: classes }...return h(this.tag, data, this.$slots.default)             }
}

路由實例的 resolve 方法

  • resolve入參的to是我們傳入的字符串’/foo’,current是當前路由this.$route,append是undefine。
  • resolve 方法內部又調用了很多函數和方法,得到需要的數據并返回。
  • 讓我們接著分析調用的函數(normalizeLocation,this.match, createHref)。
// ./router.js
export default class VueRouter {...resolve (to: RawLocation,current?: Route,append?: boolean) {...const location = normalizeLocation(to, current, append, this)const route = this.match(location, current)const fullPath = route.redirectedFrom || route.fullPathconst base = this.history.baseconst href = createHref(base, fullPath, this.mode) // this.mode 看做 'hash' 即可return {location,route,href...}                      }
}

normalizeLocation 函數分析

  • 入參說明:raw = ‘/foo’, current = this.route, append = undifune, router = this.$router
  • parsePath函數暫時沒有額外影響,這里不做分析,只是說明 parsePath 的具體內容
  • 最終返回一個對象,里面有 _normalized: true 和 path: '/foo’相關內容。
// ./util/location.js
export function normalizeLocation(raw: RawLocation,current: ?Route,append: ?boolean,router: ?VueRouter
): Location {let next: Location = typeof raw === 'string' ? { path: raw } : rawif (next._normalized) {return next    }...// parsePath 的實際內容為 {'path': '/foo', 'query': '', 'hash': ''}const parsedPath = parsePath(next.path || '')// basePath 為當前的路由的路徑const basePath = (current && current.path) || '/'// resolvePath函數對'/foo'也沒有額外影響,可以理解直接返回了'/foo'賦值給pathconst path = parsedPath.path? resolvePath(parsedPath.path, basePath, append || next.append): basePath...return {_normalized: true,path,...    }
}

this.match方法獲得的route是什么

  • 對應代碼 const route = this.match(location, current),current = this.$route。
  • match方法和resolve方法一樣,是定義在VueRouter中的,它直接返回了路由匹配器的match方法。
  • 路由匹配器中的match方法會遍歷pathList和pathMap,利用正則表達式查看對應的path是否匹配,如果匹配,這里則返回 _createRoute 函數調用。
    • pathList和pathMap是在初始化router時生成的,這里為方便理解,再說明一下。
    • pathList是一個數組,記錄著我們初始化時定義的各個url path,例如’/foo’,‘/bar’
    • pathMap是一個哈希結構,key為path,value為相關的數據(比如path, component, regex等等)。
  • _createRoute 函數又調用了 ./util/route.js 的 createRoute 函數。它返回了一個被凍結的對象,里面主要有path和matched屬性,matched在這里可以看做等于 [record]。
  • 所以this,match方法返回的是一個和我們輸入的路徑to匹配的一個route對象,里面有我們需要的path,record等內容。
// ./router.js
export default class VueRouter {...match (raw: RawLocation, current?: Route, redirectedFrom?: Location): Route {return this.matcher.match(raw, current, redirectedFrom)}
}// ./create-matcher.js
export function createMatcher(...) {...function match {raw: RawLocation,currentRoute?: Route,redirectedFrom?: Location}: Route {// 由于傳入的raw是已經標準化過的,所以這里的location和raw沒有任何區別const location = normalizedLocation(raw, currentRoute, false, router)const { name } = locationif (name) {...        } else if (location.path) {location.params = {}for (let i = 0; i < pathList.length; i++) {const path = pathList[i]const record = pathMap[path]if (matchRoute(record.regex, location.path, location.param)) {return _createRoute(record, location, redirectedFrom)                }            }                    }}function matchRoute(regex: RouteRegExp,path: string,params: Object): boolean {const m = path.match(regex)if (!m) {return false    } else if (!params) {return true    }...return true}function _createRoute(record: ?RouteRecord,location: Location,redirectedFrom?: Location            ): Route {...return createRoute(record, location. redirectedFrom, router)    }
}// ./util/route.js
export function createRoute(record: ?RouteRecord,location: Location,redirectedFrom?: ?Location,router?: VueRouter
): Route {const route: Route = {path: location.path || '/',matched: record ? formatMatch(record) :[], // 這里可以先簡單理解為 [record]...            }return Object.freeze(route)
}

createHref函數分析

  • 對應代碼 href = createHref(base, fullPath, this.mode),對應base = undefine, fullPath = ‘/foo’, this.mode = ‘hash’。
  • 在vue-route中,默認為hash模式,所以所有的的path前面都會帶一個#號
  • 這個#號就是在這個函數中體現的
// ./router.js
function createHref(base: string, fullPath: string, mode) {var path = mode === 'hash' ? '#' + fullPath : fullPathreturn base ? cleanPath(base + '/' + path) : path
}

總結

  • recolve返回的對象里面的內容主要為location, route , href。
  • location是標準化后的to,并且打上了標記表示已標準化,防止多次標準化,提升效率。
  • route是通過遍歷pathList和pathMap,利用正則表達式找到的和to匹配的路由對象,里面包含很多需要的內容。
  • href在默認的hash模式下,會在to的前面加上#號,例如這里的’#/foo’。
// ./router.jsexport default class VueRouter {...resolve(to, current, append) {const location = normalizeLocation(to, current, append, this)const route = this.match(location, current)const fullPath = route.redirectedFrom || route.fullPathconst base = this.history.baseconst href = createHref(base, fullPath, this.mode)return {location,route,href,...        }    }
}
  • 后續的內容就是vue利用h函數將link組件渲染為html的內容,例如設置類名,定義handler函數處理跳轉,綁定點擊事件,指定 a 標簽等等。
  • 這里再對vue-router官方文檔中提到的匹配成功后自動設置的class屬性值,通過源碼分析一下:
    • 通過下面的代碼可以看出,如果你不想要 router-link-active 的類名,可以在初始化router時,加入options.linkActiveClass屬性就可以了

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/22398.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/22398.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/22398.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

CSS選擇器和樣式

CSS CSS&#xff1a;選擇器&#xff1a;通配符選擇器&#xff1a;基本選擇器&#xff1a;標簽選擇器&#xff1a;類選擇器&#xff1a;ID選擇器&#xff1a;基本選擇器的優先級別: 群組選擇器:派生選擇器&#xff1a;后代選擇器&#xff1a;子代選擇器&#xff1a;相鄰兄弟選擇…

sed批量修改shell腳本內容

需求:郵件服務器腳本ip做了切換,由原先的11.22.33.44,切換為11.22.33.55 需要把所有使用了11.22.33.44該ip的腳本改為11.22.33.55 示例: #建2個測試文件 cat test1.txt 11.22.33.44 hello 11.22.33.44cat test2.txt 11.22.33.44 world#1.先找出哪些腳本包含該ip grep 11.22.3…

正邦科技(day3)

出廠測試 設備校準 這個需要注意的是校準電流、電壓、電感的時候有時候負感器會裝反&#xff0c;mcu會壞&#xff0c;需要flash一下清空內存

【貓狗識別系統】圖像識別Python+TensorFlow+卷積神經網絡算法+人工智能深度學習

貓狗識別系統。通過TensorFlow搭建MobileNetV2輕量級卷積神經算法網絡模型&#xff0c;通過對貓狗的圖片數據集進行訓練&#xff0c;得到一個進度較高的H5格式的模型文件。然后使用Django框架搭建了一個Web網頁端可視化操作界面。實現用戶上傳一張圖片識別其名稱。 一、前言 …

iptables備份

備份 iptables sudo iptables-save > iptables_backup.txt文件還原

【安裝筆記-20240529-Windows-poedit 翻譯編輯器】

安裝筆記-系列文章目錄 安裝筆記-20240529-Windows-Poedit 翻譯編輯器 文章目錄 安裝筆記-系列文章目錄安裝筆記-20240529-Windows-Poedit 翻譯編輯器 前言一、軟件介紹名稱&#xff1a;Poedit主頁官方介紹 二、安裝步驟測試版本&#xff1a;Poedit-3.4.4下載鏈接安裝界面 三、…

華為機械工程師面試問題

在機械工程師的面試中,面試官可能會提出一系列問題,以評估應聘者的專業知識、技能、經驗以及解決問題的能力。以下是一些可能的面試題: 基礎知識與技能: 請解釋機械工程中常用的幾種傳動方式,并比較它們的優缺點。描述一下你在機械設計過程中常用的軟件,并舉例說明你是如…

網絡安全設備常見部署模式介紹

文章目錄 前言串聯模式路由模式透明模式 旁路模式旁路監聽代理模式正向代理透明代理反向代理 前言 網絡安全設備主要有串聯模式和旁路模式。這些模式在網絡安全架構中扮演著關鍵角色&#xff0c;以確保數據傳輸的安全性和高效性。 串聯模式 串聯模式要求所有流量都必須通過安…

程序員為什么會成為工具人——及其一些破局的思考

一、程序員為什么會成為工具人 程序員為什么會成為工具人的因素分析 序號因素分析1 技術從來不是解決用戶價值問題的那個人&#xff0c;產品才是解決用戶需求痛點創造價值問題的那個人 &#xff08;技術只是服務于產品的工具&#xff0c;程序員永遠都是在做最后一公里的搬磚&am…

Linux 命令 find 的深度解析與使用

Linux 命令 find 的深度解析與使用 在 Linux 系統中&#xff0c;find 命令是一個功能強大的工具&#xff0c;用于在文件系統中搜索文件或目錄。無論是基于文件名、文件類型、文件大小、文件權限&#xff0c;還是基于文件的最后修改時間等&#xff0c;find 命令都能提供靈活的搜…

Windows家庭版 WSL2非C盤詳細安裝配置與WSL代理設置+WSL基礎環境CUDA安裝

1 WSL2 配置 1.1 WSL 開啟 注意&#xff1a;需要在windows功能中開啟“Hyper-V”和“適用于Linux的Windows子系統”功能 但是&#xff01;windows家庭版&#xff08;windows home&#xff09;是默認沒有Hyper-V功能的&#xff0c;自己手動安裝&#xff1a; 創建一個記事本&a…

前端面試寶典總結4-手搓代碼JavaScript(基礎版)

前端面試寶典總結4之手寫代碼JavaScript&#xff08;基礎版&#xff09; 本文章 對各大學習技術論壇知識點&#xff0c;進行總結、歸納自用學習&#xff0c;共勉&#x1f64f; 上一篇&#x1f449;: 前端面試寶典總結4-手搓代碼JavaScript&#xff08;數據處理&#xff09; 文…

R語言學習 - 柱狀圖

柱狀圖繪制 柱狀圖也是較為常見的一種數據展示方式&#xff0c;可以展示基因的表達量&#xff0c;也可以展示GO富集分析結果&#xff0c;基因注釋數據等。這篇轉錄組工具比較 轉錄組分析工具哪家強&#xff1f;中就使用到比較多堆積柱狀圖。 常規矩陣柱狀圖繪制 有如下4個基…

Audio PsyChat:web端語音心理咨詢系統

這是一個在服務器本地運行的web語音心理咨詢系統&#xff0c;咨詢系統內核使用PsyChat&#xff0c;我們為其制作了Web前端&#xff0c;并拼接了ASR和TTS組件&#xff0c;使局域網內用戶可以通過單純的語音進行交互。其中ASR和TTS組件使用PaddleSpeech API。 使用 使用單卡3090…

信息學奧賽初賽天天練-19-挑戰程序閱讀-探索因數、所有因數平和、質數的奧秘

PDF文檔公眾號回復關鍵字:20240604 1 2023 CSP-J 閱讀程序3 閱讀程序&#xff08;程序輸入不超過數組成字符串定義的范圍&#xff1a;判斷題正確填√&#xff0c;錯誤填&#xff1b;除特殊說明外&#xff0c;判斷題1.5分&#xff0c;選擇題3分&#xff0c;共計40分&#xff…

C++中的靜態變量與普通變量

在C中&#xff0c;變量的存儲和生命周期可以根據其定義的位置和方式而有所不同。特別是&#xff0c;靜態變量&#xff08;無論是靜態局部變量還是靜態全局變量&#xff09;與普通的全局變量和局部變量在行為和生命周期上有顯著的區別。 局部變量 局部變量是在函數內部定義的變…

【微信支付】獲取微信開發信息(全網最詳細!!!)

前言 1、申請商戶號 申請流程與資料 詳細申請步驟 申請開通接入微信支付步驟 2、申請微信小程序 申請小程序步驟 查看小程序AppID 3、微信支付普通商戶與AppID賬號關聯 4、獲取開發中需要的密鑰和證書 4.1、申請證書 4.2、下載證書工具 4.3、證書工具—填寫商戶信息…

如何進行團隊協作

團隊協作是項目管理中不可或缺的一部分&#xff0c;它涉及多個團隊成員共同工作以達成共同的目標。以下是一些關于如何進行團隊協作的建議&#xff1a; 1. 明確目標和角色 設定清晰的目標&#xff1a;確保所有團隊成員都清楚了解項目的總體目標以及他們各自在其中的角色和職責…

關于微積分的幾個問題回顧

1.定積分求解舉例 定積分是微積分中的一個重要概念&#xff0c;用于求解連續函數在某一區間上的面積或體積等問題。下面我將給出一個定積分求解的舉例。 假設我們要求解函數 f(x)x2 在區間 [0,1] 上的定積分&#xff0c;即求解 ∫01?x2dx 求解步驟 1. 找出被積函數 f(x) …

3D分割之SAGA訓練流程解讀

訓練之前,會先提取2種特征, 一種是每張圖片的image encoding, 它的size是(64,64),代表每個像素處的特征向量。這個向量用于特征匹配(選中的目標和每個像素的相似度)。 一種是SAM提取的所有mask(用于計算mask所在目標的特征向量)。 extract_features.py提取的是SAM模型…