UNPKG

@esmx/router-vue

Version:

Vue integration for @esmx/router - A universal router that works seamlessly with both Vue 2.7+ and Vue 3

571 lines (429 loc) 11.8 kB
<div align="center"> <img src="https://esmx.dev/logo.svg?t=2025" width="120" alt="Esmx Logo" /> <h1>@esmx/router-vue</h1> <div> <a href="https://www.npmjs.com/package/@esmx/router-vue"> <img src="https://img.shields.io/npm/v/@esmx/router-vue.svg" alt="npm version" /> </a> <a href="https://github.com/esmnext/esmx/actions/workflows/build.yml"> <img src="https://github.com/esmnext/esmx/actions/workflows/build.yml/badge.svg" alt="Build" /> </a> <a href="https://esmx.dev/coverage/"> <img src="https://img.shields.io/badge/coverage-live%20report-brightgreen" alt="Coverage Report" /> </a> <a href="https://nodejs.org/"> <img src="https://img.shields.io/node/v/@esmx/router-vue.svg" alt="node version" /> </a> <a href="https://bundlephobia.com/package/@esmx/router-vue"> <img src="https://img.shields.io/bundlephobia/minzip/@esmx/router-vue" alt="size" /> </a> </div> <p><a href="https://github.com/esmnext/esmx/tree/master/packages/router">@esmx/router</a> 的 Vue 集成包 - 一个同时适用于 Vue 2.7+ 和 Vue 3 的通用路由器。</p> <p> <a href="https://github.com/esmnext/esmx/blob/master/packages/router-vue/README.md">English</a> | 中文 </p> </div> ## 🚀 特性 ✨ **通用 Vue 支持** - 同时支持 Vue 2.7+ 和 Vue 3 🎯 **组合式 API 优先** - 为现代 Vue 开发而构建 🔗 **无缝集成** - Vue Router 的替代方案 🚀 **TypeScript 就绪** - 完整的 TypeScript 支持,出色的开发体验 ⚡ **高性能** - 为生产环境优化 🔄 **SSR 兼容** - 支持服务端渲染 ## 📦 安装 ```bash # npm npm install @esmx/router @esmx/router-vue # pnpm pnpm add @esmx/router @esmx/router-vue # yarn yarn add @esmx/router @esmx/router-vue ``` ## 🚀 快速开始 ### Vue 3 ```typescript import { createApp, h } from 'vue'; import { Router, RouterMode } from '@esmx/router'; import { RouterPlugin, useProvideRouter } from '@esmx/router-vue'; import App from './App.vue'; const routes = [ { path: '/', component: () => import('./views/Home.vue') }, { path: '/about', component: () => import('./views/About.vue') } ]; const router = new Router({ routes, mode: RouterMode.history }); const app = createApp({ setup() { useProvideRouter(router); return {}; }, render: () => h(App) }); // 安装插件 app.use(RouterPlugin); app.mount('#app'); ``` ### Vue 2.7+ ```typescript import Vue from 'vue'; import { Router, RouterMode } from '@esmx/router'; import { RouterPlugin, useProvideRouter } from '@esmx/router-vue'; import App from './App.vue'; const routes = [ { path: '/', component: () => import('./views/Home.vue') }, { path: '/about', component: () => import('./views/About.vue') } ]; const router = new Router({ routes, mode: RouterMode.history }); // 安装插件 Vue.use(RouterPlugin); new Vue({ setup() { useProvideRouter(router); }, render: h => h(App) }).$mount('#app'); ``` ## 基础用法 ### 模板用法 ```vue <template> <div id="app"> <nav> <RouterLink to="/">首页</RouterLink> <RouterLink to="/about">关于</RouterLink> <RouterLink to="/users/123">用户资料</RouterLink> </nav> <!-- 路由组件将在这里渲染 --> <RouterView /> </div> </template> ``` ### 组合式 API ```vue <script setup lang="ts"> import { useRouter, useRoute } from '@esmx/router-vue'; import { watch } from 'vue'; const router = useRouter(); const route = useRoute(); // 编程式导航 const goToAbout = () => { router.push('/about'); }; const goBack = () => { router.back(); }; // 监听路由变化 watch(() => route.path, (newPath) => { // 处理路由变化逻辑 }); </script> <template> <div> <h1>{{ route.meta?.title || '页面' }}</h1> <p>当前路径: {{ route.path }}</p> <p>路由参数: {{ JSON.stringify(route.params) }}</p> <p>查询参数: {{ JSON.stringify(route.query) }}</p> <button @click="goToAbout">前往关于页</button> <button @click="goBack">返回</button> </div> </template> ``` ### 选项式 API ```vue <script> import { defineComponent } from 'vue'; import { getRouter, getRoute } from '@esmx/router-vue'; export default defineComponent({ mounted() { const router = getRouter(this); const route = getRoute(this); // 访问当前路由信息 }, methods: { navigate() { const router = getRouter(this); router.push('/dashboard'); } } }); </script> ``` ## 📚 API 参考 ### 组件 #### RouterLink 用于创建导航链接的组件。 **属性:** | 属性 | 类型 | 默认值 | 描述 | |------|------|---------|-------------| | `to` | `string` \| `RouteLocationInput` | - | 目标路由位置 | | `type` | `RouterLinkType` | `'push'` | 导航类型 (`'push'` \| `'replace'` \| `'pushWindow'` \| `'replaceWindow'` \| `'pushLayer'`) | | `exact` | `RouteMatchType` | `'include'` | 激活状态匹配方式 (`'include'` \| `'exact'` \| `'route'`) | | `activeClass` | `string` | - | 激活状态的 CSS 类名 | | `event` | `string` \| `string[]` | `'click'` | 触发导航的事件 | | `tag` | `string` | `'a'` | 要渲染的 HTML 标签 | | `layerOptions` | `RouterLayerOptions` | - | 弹层导航选项 (与 `type="pushLayer"` 一起使用) | **用法:** ```vue <template> <!-- 基础链接 --> <RouterLink to="/home">首页</RouterLink> <!-- 替换导航 --> <RouterLink to="/login" type="replace">登录</RouterLink> <!-- 自定义样式 --> <RouterLink to="/dashboard" active-class="nav-active" exact="exact" > 仪表板 </RouterLink> <!-- 自定义标签 --> <RouterLink to="/submit" tag="button" class="btn"> 提交 </RouterLink> </template> ``` #### RouterView 渲染匹配路由组件的组件。 **用法:** ```vue <template> <div> <!-- 根级路由在这里渲染 --> <RouterView /> <!-- 嵌套路由会在子 RouterView 组件中渲染 --> <!-- 每个 RouterView 会自动处理正确的深度 --> </div> </template> ``` ### 组合式 API #### useRouter() 获取用于导航的路由器实例。 ```typescript function useRouter(): Router ``` **用法:** ```vue <script setup> import { useRouter } from '@esmx/router-vue'; const router = useRouter(); const navigate = () => { router.push('/about'); }; </script> ``` #### useRoute() 获取当前路由信息(响应式)。 ```typescript function useRoute(): Route ``` **用法:** ```vue <script setup> import { useRoute } from '@esmx/router-vue'; const route = useRoute(); // 访问路由属性 // route.path - 当前路径 // route.params - 路由参数 // route.query - 查询参数 // route.meta - 路由元数据 </script> ``` #### useProvideRouter() 为子组件提供路由上下文。 ```typescript function useProvideRouter(router: Router): void ``` **用法:** ```typescript import { Router, RouterMode } from '@esmx/router'; import { useProvideRouter } from '@esmx/router-vue'; const router = new Router({ routes, mode: RouterMode.history }); // 在应用的 setup 函数中 setup() { useProvideRouter(router); } ``` #### useLink() 为自定义导航组件创建响应式链接助手。 ```typescript function useLink(props: RouterLinkProps): ComputedRef<RouterLinkResolved> ``` **用法:** ```vue <script setup> import { useLink } from '@esmx/router-vue'; const link = useLink({ to: '/home', type: 'push', exact: 'include' }).value; </script> <template> <a v-bind="link.attributes" v-on="link.createEventHandlers()" :class="{ active: link.isActive }" > 自定义链接 </a> </template> ``` ### 选项式 API #### getRouter() 在选项式 API 组件中获取路由器实例。 ```typescript function getRouter(instance: VueInstance): Router ``` #### getRoute() 在选项式 API 组件中获取当前路由。 ```typescript function getRoute(instance: VueInstance): Route ``` ### 插件 #### RouterPlugin 全局注册 RouterLink 和 RouterView 组件的 Vue 插件。 ```typescript const RouterPlugin = { install(app: App): void } ``` **用法:** ```typescript // Vue 3 app.use(RouterPlugin); // Vue 2 Vue.use(RouterPlugin); ``` ## TypeScript 支持 此包为 Vue 2.7+ 和 Vue 3 提供完整的 TypeScript 支持。对于选项式 API 用法,包会自动为 Vue 组件实例增强 `$router` 和 `$route` 属性,允许您在模板和组件方法中直接访问它们。 ```typescript // 选项式 API 类型增强(自动) declare module 'vue/types/vue' { interface Vue { readonly $router: Router; readonly $route: Route; } } ``` **选项式 API 用法:** ```vue <template> <div> <!-- 直接访问,无需 'this.' --> <p>当前路径: {{ $route.path }}</p> <button @click="navigate">跳转到关于页面</button> </div> </template> <script lang="ts"> import { defineComponent } from 'vue'; export default defineComponent({ methods: { navigate() { // TypeScript 能够识别 $router 和 $route this.$router.push('/about'); // Access current route: this.$route.path } } }); </script> ``` ## 高级用法 ### 自定义链接组件 ```vue <script setup lang="ts"> import { useLink } from '@esmx/router-vue'; import type { RouterLinkProps } from '@esmx/router'; interface Props extends RouterLinkProps { icon?: string; disabled?: boolean; } const props = defineProps<Props>(); const link = useLink(props).value; </script> <template> <button v-bind="link.attributes" v-on="link.createEventHandlers()" :class="{ active: link.isActive, disabled: disabled }" :disabled="disabled" > <i v-if="icon" :class="icon" /> <slot /> </button> </template> ``` ### 组件中的路由守卫 ```vue <script setup> import { useRouter, useRoute } from '@esmx/router-vue'; import { onMounted, onBeforeUnmount } from 'vue'; const router = useRouter(); const route = useRoute(); onMounted(() => { // 添加路由守卫 const unregister = router.beforeEach((to, from) => { // 检查路由是否需要认证(isAuthenticated 是你的认证函数) if (to.meta?.requiresAuth && !isAuthenticated()) { return '/login'; } }); // 组件卸载时清理 onBeforeUnmount(unregister); }); </script> ``` ## 从 Vue Router 迁移 ### 主要差异 1. **路由器创建**: 使用 `@esmx/router` 的 `new Router()` 构造函数 2. **上下文提供**: 使用 `useProvideRouter()` 而非路由器安装 3. **组件注册**: 使用 `RouterPlugin` 进行全局组件注册 ### 迁移示例 **之前 (Vue Router):** ```typescript import { createRouter, createWebHistory } from 'vue-router'; const router = createRouter({ history: createWebHistory(), routes }); app.use(router); ``` **之后 (@esmx/router-vue):** ```typescript import { Router, RouterMode } from '@esmx/router'; import { RouterPlugin, useProvideRouter } from '@esmx/router-vue'; import { createApp, h } from 'vue'; import App from './App.vue'; const router = new Router({ routes, mode: RouterMode.history }); const app = createApp({ setup() { useProvideRouter(router); return {}; }, render: () => h(App) }); app.use(RouterPlugin); ``` ## 浏览器支持 - **现代浏览器**:支持 ES 模块 (`import`/`export`) 和动态导入 (`import()`) 的浏览器 ## 贡献 我们欢迎贡献!请随时提交 issues 和 pull requests。 ## 📄 许可证 MIT © [Esmx 团队](https://github.com/esmnext/esmx) ## 相关包 - [@esmx/router](https://github.com/esmnext/esmx/tree/master/packages/router) - 核心路由包 - [@esmx/core](https://github.com/esmnext/esmx/tree/master/packages/core) - Esmx 核心框架