当前位置: 首页 > news >正文

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

相关文章:

  • go|context源码解析
  • 极坐标求解的二重积分适合特征
  • Python(十四)
  • 飞致云开源社区月度动态报告(2025年5月)
  • 【数据结构】——二叉树--链式结构
  • 考研系列—操作系统:第四章、文件管理(part.1)
  • C++ 栈(Stack)与队列(Queue)深度解析:从原理到实战
  • Linux 网络流量监控实战:使用 iftop 精准定位高带宽连接
  • 前端面经 websocket
  • 第四十一天打卡
  • Azure DevOps 管道部署系列之二IIS
  • Oracle DG库控制文件IO错误导致宕机的应急处理
  • 赛博算命之“帝王之术”——奇门遁甲的JAVA实现
  • Redis最佳实践——安全与稳定性保障之数据持久化详解
  • 普中STM32F103ZET6开发攻略(一)
  • Java代码重构:如何提升项目的可维护性和扩展性?
  • Android之ListView
  • 第十二节:第三部分:集合框架:List系列集合:特点、方法、遍历方式、ArrayList集合的底层原理
  • TK海外抢单源码/指定卡单
  • 车载诊断架构SOVD --- 车辆发现与建连
  • 手机网站自适应分辨率/系统优化的意义
  • html5自适应手机网站模板/小果seo实战培训课程
  • 网站建设主机的功能/凤山网站seo
  • 有哪些是外国人做的网站/可以免费推广的平台
  • 优设网网站设计评价/怎么下载百度
  • 离退休干部网站建设/无锡百度快速优化排名