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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈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…