Vue-Router簡版手寫實現

1.?路由庫工程設計

首先,我們需要創建幾個核心文件來組織我們的路由庫:

src/router/index.tsRouterView.tsRouterLink.tsuseRouter.tsinjectionsymbols.tshistory.ts

2.?injectionSymbols.ts

定義一些注入符號來在應用中共享狀態:

import { inject, provide, InjectionKey, Ref } from 'vue';export interface Router {currentRoute: Ref<Route>;push: (to: string) => void;replace: (to: string) => void;resolve: (to: string) => string;
}export interface Route {path: string;component: any;
}export const routerKey: InjectionKey<Router> = Symbol('router');
export const matchedRouteKey: InjectionKey<Ref<Route>> = Symbol('matchedRoute');
export const viewDepthKey: InjectionKey<number> = Symbol('viewDepth');export function provideRouter(router: Router) {provide(routerKey, router);
}export function useRouter(): Router {return inject(routerKey);
}export function useMatchedRoute(): Ref<Route> {return inject(matchedRouteKey);
}export function provideMatchedRoute(route: Ref<Route>) {provide(matchedRouteKey, route);
}export function useViewDepth(): number {return inject(viewDepthKey, 0);
}export function provideViewDepth(depth: number) {provide(viewDepthKey, depth);
}

3. RouterView.ts

實現RouterView組件:

import { defineComponent, h, computed } from 'vue';
import { useMatchedRoute, useViewController, provideViewController } from './injectionsymbols';export const RouterView = defineComponent({name: 'RouterView',setup() {const depth = useViewController();const matchedRoute = useMatchedRoute();const route = computed(() => matchedRoute.value[depth]);provideViewController(depth + 1);return () => {const Component = route.value && route.value.component;return Component ? h(Component) : null;};}
});

4. RouterLink.ts

實現RouterLink組件:

import { defineComponent, h } from 'vue';
import { useRouter } from './injectionsymbols';export const RouterLink = defineComponent({name: 'RouterLink',props: {to: {type: [String, Object],required: true},replace: Boolean},setup(props, { slots }) {const router = useRouter();const navigate = (event: Event) => {event.preventDefault();if (props.replace) {router.replace(props.to as string);} else {router.push(props.to as string);}};return () => {return h('a', {href: router.resolve(props.to as string),onClick: navigate}, slots.default ? slots.default() : '');};}
});

5. useRouter.ts

實現useRouter函數:

import { inject } from 'vue';
import { routerKey, Router } from './injectionSymbols';export function useRouter(): Router {return inject(routerKey);
}

6. index.ts

實現createRouter函數:

import { ref, reactive, watch, Ref } from 'vue';
import { provideRouter, provideMatchedRoute, Route, Router } from './injectionsymbols';export function createRouter({ history, routes }: { history: any, routes: Route[] }): Router {const currentRoute: Ref<Route> = ref({ path: '/', component: null });function createMatcher(routes: Route[]) {const matchers = routes.map(route => ({...route,regex: new RegExp(`^${route.path}$`)}));return (path: string) => matchers.find(route => route.regex.test(path));}const matcher = createMatcher(routes);function push(to: string) {const route = matcher(to);if (route) {currentRoute.value = route;history.push(to);}}function replace(to: string) {const route = matcher(to);if (route) {currentRoute.value = route;history.replace(to);}}const router: Router = {currentRoute,push,replace,resolve: (to: string) => to};watch(currentRoute, (route) => {provideMatchedRoute(ref(route));});provideRouter(router);return router;
}

7. history.ts

實現createWebHistory函數:

export function createWebHistory() {const listeners: ((path: string) => void)[] = [];window.addEventListener('popstate', () => {listeners.forEach(listener => listener(window.location.pathname));});function push(path: string) {window.history.pushState({}, '', path);listeners.forEach(listener => listener(path));}function replace(path: string) {window.history.replaceState({}, '', path);listeners.forEach(listener => listener(path));}function listen(callback: (path: string) => void) {listeners.push(callback);}return {push,replace,listen};
}

8.?示例應用

最后,我們可以在一個簡單的 Vue 應用中使用我們的自定義路由庫:

// main.ts
import { createApp } from 'vue';
import App from './App.vue';
import { createRouter } from './router';
import { createWebHistory } from './router/history';const routes = [{ path: '/', component: () => import('./components/Home.vue') },{ path: '/about', component: () => import('./components/About.vue') }
];const history = createWebHistory();
const router = createRouter({ history, routes });createApp(App).use(router).mount('#app');

以下是在App.vue中

// App.vue
<template><div id="app"><router-link to="/">Home</router-link><router-link to="/about">About</router-link><router-view></router-view></div>
</template><script lang="ts">
import { defineComponent } from 'vue';export default defineComponent({name: 'App'
});
</script>

這個簡化版的 Vue Router 庫的 TypeScript 版本包含了核心組件 RouterView、RouterLink 以及核心 API createRouter 和 useRouter,實現了基本的路由功能。通過這個實現,你可以了解 Vue Router 的基本工作原理和核心概念。

9.?補充資料

vue-router 官方文檔:https://router.vuejs.org/zh/introduction.html

vue-router 相關 api 速查:https://router.vuejs.org/zh/api/

源碼:https://github.com/vuejs/router

瀏覽器歷史記錄協議:https://developer.mozilla.org/en-US/docs/Web/API/History_API

路由庫實現:https://github.com/vuejs/router/blob/v4.3.3/packages/router/src/history/html5.ts

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

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

相關文章

Electron-vite【實戰】MD 編輯器 -- 文件列表(含右鍵快捷菜單,重命名文件,刪除本地文件,打開本地目錄等)

最終效果 頁面 src/renderer/src/App.vue <div class"dirPanel"><div class"panelTitle">文件列表</div><div class"searchFileBox"><Icon class"searchFileInputIcon" icon"material-symbols-light:…

Remote Sensing投稿記錄(投稿郵箱寫錯、申請大修延期...)風雨波折投稿路

歷時近一個半月&#xff0c;我中啦&#xff01; RS是中科院二區&#xff0c;2023-2024影響因子4.2&#xff0c;五年影響因子4.9。 投稿前特意查了下預警&#xff0c;發現近五年都不在預警名單中&#xff0c;甚至最新中科院SCI分區&#xff08;2025年3月&#xff09;在各小類上…

吉林第三屆全國龍舟邀請賽(大安站)激情開賽

龍舟競渡處,瑞氣滿湖光。5月31日&#xff0c;金蛇獻瑞龍舞九州2025年全國龍舟大聯動-中國吉林第三屆全國龍舟邀請賽(大安站)“嫩江灣杯”白城市全民健身龍舟賽在吉林大安嫩江灣國家5A級旅游區玉龍湖拉開帷幕。 上午9時&#xff0c;伴隨著激昂的音樂&#xff0c;活力四射的青春舞…

華為OD機試真題——通過軟盤拷貝文件(2025A卷:200分)Java/python/JavaScript/C++/C語言/GO六種最佳實現

2025 A卷 200分 題型 本文涵蓋詳細的問題分析、解題思路、代碼實現、代碼詳解、測試用例以及綜合分析; 并提供Java、python、JavaScript、C++、C語言、GO六種語言的最佳實現方式! 本文收錄于專欄:《2025華為OD真題目錄+全流程解析/備考攻略/經驗分享》 華為OD機試真題《通過…

一起學數據結構和算法(二)| 數組(線性結構)

數組&#xff08;Array&#xff09; 數組是最基礎的數據結構&#xff0c;在內存中連續存儲&#xff0c;支持隨機訪問。適用于需要頻繁按索引訪問元素的場景。 簡介 數組是一種線性結構&#xff0c;將相同類型的元素存儲在連續的內存空間中。每個元素通過其索引值&#xff08;數…

ZYNQ sdk lwip配置UDP組播收發數據

?? 一、顛覆認知:組播 vs 單播 vs 廣播 通信方式目標設備網絡負載典型應用場景單播1對1O(n)SSH遠程登錄廣播1對全網O(1)ARP地址解析組播1對N組O(1)視頻會議/物聯網群控創新價值:在智能工廠中,ZYNQ通過組播同時控制100臺AGV小車,比傳統單播方案降低92%網絡流量! ?? 二、…

機器學習:欠擬合、過擬合、正則化

本文目錄&#xff1a; 一、欠擬合二、過擬合三、擬合問題原因及解決辦法四、正則化&#xff1a;盡量減少高次冪特征的影響&#xff08;一&#xff09;L1正則化&#xff08;二&#xff09;L2正則化&#xff08;三&#xff09;L1正則化與L2正則化的對比 五、正好擬合代碼&#xf…

Linux命令之ausearch命令

一、命令簡介 ausearch 是 Linux 審計系統 (auditd) 中的一個實用工具,用于搜索審計日志中的事件。它是審計框架的重要組成部分,可以幫助系統管理員分析系統活動和安全事件。 二、使用示例 1、安裝ausearch命令 Ubuntu系統安裝ausearch命令,安裝后啟動服務。 root@testser…

mac電腦安裝nvm

方案一、常規安裝 下載安裝腳本&#xff1a;在終端中執行以下命令來下載并運行 NVM 的安裝腳本3&#xff1a; bash curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.39.5/install.sh | bash配置環境變量&#xff1a;安裝完成后&#xff0c;需要配置環境變量。如…

Excel 操作 轉圖片,轉pdf等

方式一 spire.xls.free&#xff08;沒找設置分辨率的方法&#xff09; macOs開發Java GUI程序提示缺少字體問題解決 Spire.XLS&#xff1a;一款Excel處理神器_spire.xls免費版和收費版的區別-CSDN博客 官方文檔 Spire.XLS for Java 中文教程 <dependency><groupI…

oracle goldengate實現遠程抽取postgresql 到 postgresql的實時同步【絕對無坑版,親測流程驗證】

oracle goldengate實現postgresql 到 postgresql的實時同步 源端&#xff1a;postgresql1 -> postgresql2 流復制主備同步 目標端&#xff1a;postgresql 數據庫版本&#xff1a;postgresql 12.14 ogg版本&#xff1a;21.3 架構圖&#xff1a; 數據庫安裝以及流復制主備…

2.從0開始搭建vue項目(node.js,vue3,Ts,ES6)

從“0到跑起來一個 Vue 項目”&#xff0c;重點是各個工具之間的關聯關系、職責邊界和技術演化脈絡。 從你寫代碼 → 到代碼能跑起來 → 再到代碼可以部署上線&#xff0c;每一步都有不同的工具參與。 &#x1f63a;&#x1f63a;1. 安裝 Node.js —— 萬事的根基 Node.js 是…

MQTT的Thingsboards的使用

訪問云服務 https://thingsboard.cloud/ 新建一個設備 彈出 默認是mosquittor的客戶端。 curl -v -X POST http://thingsboard.cloud/api/v1/tnPrO76AxF3TAyOblf9x/telemetry --header Content-Type:application/json --data "{temperature:25}" 換成MQTTX的客戶…

金磚國家人工智能高級別論壇在巴西召開,華院計算應邀出席并發表主題演講

當地時間5月20日&#xff0c;由中華人民共和國工業和信息化部&#xff0c;巴西發展、工業、貿易與服務部&#xff0c;巴西公共服務管理和創新部以及巴西科技創新部聯合舉辦的金磚國家人工智能高級別論壇&#xff0c;在巴西首都巴西利亞舉行。 中華人民共和國工業和信息化部副部…

BLE協議全景圖:從0開始理解低功耗藍牙

BLE(Bluetooth Low Energy)作為一種針對低功耗場景優化的通信協議,已經廣泛應用于智能穿戴、工業追蹤、智能家居、醫療設備等領域。 本文是《BLE 協議實戰詳解》系列的第一篇,將從 BLE 的發展歷史、協議棧結構、核心機制和應用領域出發,為后續工程實戰打下全面認知基礎。 …

表單校驗代碼和樹形結構值傳遞錯誤解決

表單校驗代碼&#xff0c;兩種方式校驗&#xff0c;自定義的一種校驗&#xff0c;與element-ui組件原始的el-form表單的校驗不一樣&#xff0c;需要傳遞props和rules過去校驗 const nextStep () > {const data taskMsgInstance.value.formDataif(data.upGradeOrg ) {elm…

vscode 配置 QtCreat Cmake項目

1.vscode安裝CmakeTool插件并配置QT中cmake的路徑&#xff0c;不止這一處 2.cmake生成器使用Ninja&#xff08;Ninja在安裝QT時需要勾選&#xff09;&#xff0c;可以解決[build] cc1plus.exe: error: too many filenames given; type ‘cc1plus.exe --help’ for usage 編譯時…

關于數據倉庫、數據湖、數據平臺、數據中臺和湖倉一體的概念和區別

我們談論數據中臺之前&#xff0c; 我們也聽到過數據平臺、數據倉庫、數據湖、湖倉一體的相關概念&#xff0c;它們都與數據有關系&#xff0c;但他們和數據中臺有什么樣的區別&#xff0c; 下面我們將圍繞數據平臺、數據倉庫、數據湖和數據中臺的區別進行介紹。 一、相關概念…

WIN11+eclipse搭建java開發環境

環境搭建&#xff08;WIN11ECLIPSE&#xff09; 安裝JAVA JDK https://www.oracle.com/cn/java/technologies/downloads/#jdk24安裝eclipse https://www.eclipse.org/downloads/ 注意&#xff1a;eclipse下載時指定aliyun的軟件源&#xff0c;后面安裝會快一些。默認是jp漢化e…

通義靈碼深度實戰測評:從零構建智能家居控制中樞,體驗AI編程新范式

一、項目背景&#xff1a;零基礎挑戰全棧智能家居系統 目標&#xff1a;開發具備設備控制、環境感知、用戶習慣學習的智能家居控制中樞&#xff08;PythonFlaskMQTTReact&#xff09; 挑戰點&#xff1a; 需集成硬件通信(MQTT)、Web服務(Flask)、前端交互(React) 調用天氣AP…