快速开始
本节帮助你在 uni-app 项目中快速集成 Uni Router,从安装到完整使用。
前置准备
确保你的项目满足以下条件:
- uni-app 项目(基于 Vue 3)
- 已有
pages.json配置文件 - 页面已在
pages.json中声明
Vue 2 不支持
Uni Router 仅兼容 Vue 3,依赖 Vue 3 的 Composition API(inject / ref)、app.provide、<script setup> 等特性。
安装
bash
pnpm add @meng-xi/uni-routerbash
npm install @meng-xi/uni-routerbash
yarn add @meng-xi/uni-router详见安装指南。
第一步:定义路由配置
创建 src/router/index.ts,定义与 pages.json 一致的路由配置:
ts
// src/router/index.ts
import { createRouter, ParamsPlugin, ChannelPlugin, InterceptorPlugin } from '@meng-xi/uni-router'
import type { RouteConfig } from '@meng-xi/uni-router'
const routes: RouteConfig[] = [
{
path: 'pages/index/index',
name: 'home',
meta: { title: '首页', isTab: true }
},
{
path: 'pages/about/about',
name: 'about',
meta: { title: '关于', requireAuth: true }
},
{
path: 'pages/login/login',
name: 'login',
meta: { title: '登录' }
},
{
path: 'pages/user/user',
name: 'user',
meta: { title: '我的', isTab: true }
}
]
const router = createRouter({
routes,
strict: true,
plugins: [ParamsPlugin, ChannelPlugin, InterceptorPlugin],
paramsPersistent: false, // 需要 ParamsPlugin
useUniEventChannel: true, // 需要 ChannelPlugin
interceptUniApi: true, // 需要 InterceptorPlugin,拦截原生 API 确保守卫生效
guardTimeout: 15000 // 守卫超时(毫秒)
})
export default router插件按需引入
plugins 中的插件按需注册,未注册的插件功能不可用(使用时抛出 PLUGIN_REQUIRED 错误)。如果你不需要参数传递或 API 拦截,只需注册需要的插件即可。详见插件系统。
推荐使用 @meng-xi/vite-plugin 从 pages.json 自动生成路由配置,避免手动维护。
第二步:注册路由器
在 main.ts 中安装路由器:
ts
// src/main.ts
import { createSSRApp } from 'vue'
import App from './App.vue'
import router from './router'
export function createApp() {
const app = createSSRApp(App)
app.use(router) // 注册 $router 和 $route 全局属性
return { app }
}第三步:配置路由守卫
在 router/index.ts 中添加守卫:
ts
// 登录状态检查
function isLoggedIn(): boolean {
return !!uni.getStorageSync('token')
}
// 全局前置守卫
router.beforeEach((to, from, next) => {
// 未登录访问受保护页面
if (to.meta.requireAuth && !isLoggedIn()) {
next(
{ name: 'login', query: { redirect: to.fullPath } },
{ mode: 'replace' }
)
return
}
// 已登录访问登录页
if (to.name === 'login' && isLoggedIn()) {
next({ name: 'home' }, { mode: 'replace' })
return
}
next()
})
// 全局后置钩子
router.afterEach((to) => {
// 自动设置页面标题
if (to.meta.title) {
uni.setNavigationBarTitle({ title: to.meta.title as string })
}
})第四步:在页面中使用
组合式 API(推荐)
vue
<!-- pages/index/index.vue -->
<template>
<view class="container">
<text>当前路径:{{ route.path }}</text>
<text>页面标题:{{ route.meta.title }}</text>
<button @click="goAbout">前往关于页</button>
<button @click="goUser">前往我的</button>
<button @click="goBack">返回</button>
</view>
</template>
<script setup lang="ts">
import { useRouter, useRoute } from '@meng-xi/uni-router'
const router = useRouter()
const route = useRoute()
async function goAbout() {
try {
await router.push({ name: 'about', query: { from: 'home' } })
} catch (err) {
console.error('导航失败:', err)
}
}
async function goUser() {
await router.push({ name: 'user' })
}
async function goBack() {
try {
await router.back()
} catch {
// 栈不足,回首页
await router.relaunch({ name: 'home' })
}
}
</script>选项式 API
vue
<template>
<view>
<text>当前路径:{{ $route.path }}</text>
<button @click="goAbout">前往关于页</button>
</view>
</template>
<script>
export default {
methods: {
goAbout() {
this.$router.push({ name: 'about', query: { id: '1' } })
},
goBack() {
this.$router.back()
}
}
}
</script>第五步:使用 RouterLink 组件
vue
<template>
<view>
<!-- 路径字符串 -->
<RouterLink to="pages/about/about">关于</RouterLink>
<!-- 命名路由 -->
<RouterLink :to="{ name: 'about' }">关于</RouterLink>
<!-- 带 query -->
<RouterLink :to="{ name: 'about', query: { id: '1' } }">关于 1</RouterLink>
</view>
</template>
<script setup>
import { RouterLink } from '@meng-xi/uni-router'
</script>第六步:处理冷启动守卫
当用户通过 H5 URL / 小程序场景值 / App deeplink 直接进入页面时,页面由 uni-app 框架直接加载,不经过路由器导航,守卫(beforeEach 等)未执行。使用 guardRoute() 可对当前页面补执行守卫链:
ts
// router/index.ts
router.isReady().then(() => {
router.guardRoute(undefined, {
onAbort: () => {
// 守卫中止:页面已加载无法阻止,手动跳转到安全页面
router.relaunch({ name: 'home' })
}
})
})路由状态自动同步
app.use(router) 安装时,路由器会注入全局 mixin,在每个页面 onShow 时自动调用 syncRoute() 同步路由状态。因此你无需手动在 App.vue 的 onShow 中调用 syncRoute()。
如果你需要在 onLoad 中获取路由信息(onLoad 早于 onShow),可手动调用:
ts
import { onLoad } from '@dcloudio/uni-app'
import { useRoute } from '@meng-xi/uni-router'
onLoad(() => {
const route = useRoute()
// 此时 route.value 可能还是旧值,手动同步
router.syncRoute()
console.log(route.value.query)
})完整示例
登录页
vue
<!-- pages/login/login.vue -->
<template>
<view class="login">
<input v-model="username" placeholder="用户名" />
<input v-model="password" type="password" placeholder="密码" />
<button @click="handleLogin" :loading="loading">登录</button>
</view>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { useRouter, useRoute } from '@meng-xi/uni-router'
const router = useRouter()
const route = useRoute()
const username = ref('')
const password = ref('')
const loading = ref(false)
async function handleLogin() {
loading.value = true
try {
const { token } = await loginApi(username.value, password.value)
uni.setStorageSync('token', token)
// 登录成功,返回原页面
const redirect = route.value.query.redirect as string
if (redirect) {
await router.replace(redirect)
} else {
await router.relaunch({ name: 'home' })
}
} catch (err) {
uni.showToast({ title: '登录失败', icon: 'none' })
} finally {
loading.value = false
}
}
async function loginApi(username: string, password: string) {
// 模拟登录 API
return new Promise<{ token: string }>((resolve) => {
setTimeout(() => resolve({ token: 'mock-token' }), 500)
})
}
</script>受保护页面
vue
<!-- pages/about/about.vue -->
<template>
<view>
<text>关于页面</text>
<text>来自:{{ route.query.from }}</text>
<button @click="goBack">返回</button>
</view>
</template>
<script setup lang="ts">
import { useRoute, useRouter } from '@meng-xi/uni-router'
const route = useRoute()
const router = useRouter()
function goBack() {
router.back()
}
</script>目录结构
完成后的项目结构:
src/
├── main.ts # 应用入口
├── App.vue # 根组件
├── pages.json # uni-app 页面配置
├── router/
│ └── index.ts # 路由器实例 + 守卫
└── pages/
├── index/
│ └── index.vue # 首页
├── about/
│ └── about.vue # 关于页
├── login/
│ └── login.vue # 登录页
└── user/
└── user.vue # 用户页