@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
Markdown
<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 核心框架