oh-router 是一个既支持 Vue 也支持 React 的路由库,它的核心功能与框架解绑,可以在 Vue 和 React 中提供一致的路由开发体验
基本使用示例
React 中使用
安装依赖
$ npm install --save oh-router oh-router-react
下面是一个结合 React 最基本的使用案例:在 StackBlitz 中打开
import { Router } from 'oh-router'
import { RouterView, Link } from 'oh-router-react'
import ReactDOM from 'react-dom/client'
const router = new Router({
routes: [
{
path: '/',
element: () => (
<div>
<div>Home</div>
<Link to="/about">to About</Link>
</div>
),
},
{
path: '/about',
element: () => (
<div>
<div>About</div>
<Link to="/">to Home</Link>
</div>
),
},
],
})
ReactDOM.createRoot(document.getElementById('root')!).render(
<RouterView router={router} />
)
Vue 中使用
安装依赖
$ npm install --save oh-router oh-router-vue
下面是一个结合 Vue 最基本的使用案例:在 StackBlitz 中打开
<div id="app">
<router-view />
</div>
<script>
import { Router } from 'oh-router'
import { installForVue } from 'oh-router-vue'
import { createApp } from 'vue'
const router = new Router({
routes: [
{
path: '/',
element: {
template: `<div>
<div>Home</div>
<router-link to="/about">to About</router-link>
</div`,
},
},
{
path: '/about',
element: {
template: `<div>
<div>About</div>
<router-link to="/">to Home</router-link>
</div`,
},
},
],
})
const app = createApp({})
app.use(installForVue(router))
app.mount('#app')
</script>
一、配置路由
React 中配置路由
import Layout from 'src/layout'
import Login from 'src/pages/login'
import User from 'src/pages/user'
import UserManager from 'src/pages/userManager'
import NotFound from 'src/pages/notFound'
const router = new Router({
routes: [
// 常规路由
{
path: '/login',
element: <Login />,
},
// 嵌套路由
{
path: '/',
element: <Layout />,
children:
// 动态路由
{
path: '/user/:id',
element: <User />
},
// 常规路由
{
// 由于该路由更加精确,所以优先级比 /user/:id 要高
// 当访问 /user/manager 时将匹配到该路由
path: '/user/manager',
element: <UserManager />
},
]
},
// 404 路由
{
path: '*',
element: <NotFound />
}
],
})
Vue 中配置路由
这部分和 React 的唯一区别就是 element 属性的类型
import Layout from 'src/layout.vue'
import Login from 'src/pages/login.vue'
import User from 'src/pages/user.vue'
import UserManager from 'src/pages/userManager.vue'
import NotFound from 'src/pages/notFound.vue'
const router = new Router({
routes: [
// 常规路由
{
path: '/login',
element: Login,
},
// 嵌套路由
{
path: '/',
element: Layout,
children:
// 动态路由
{
path: '/user/:id',
element: User
},
// 常规路由
{
// 由于该路由更加精确,所以优先级比 /user/:id 要高
// 当访问 /user/manager 时将匹配到该路由
path: '/user/manager',
element: UserManager
},
]
},
// 404 路由
{
path: '*',
element: NotFound
}
],
})
二、路由导航
oh-router 提供了三种路由导航方式:
- 通过
Router.navigate、Router.back方法 - 通过
useNavigate获取一个导航方法 - 通过
<Link>组件进行路由导航
React 中路由导航
// 1. Router.navigate,这里的 router 即是上面创建的 Router 对象
router.navigate('/user/manager')
router.navigate('/user/manager', {replace: true})
router.navigate(-2)
router.back()
function User() {
// 2. useNavigate
const navigate = useNavigate()
navigate('/user/manager')
navigate('/user/manager', {replace: true})
navigate(-2)
// 3. <Link>
return <div>
<Link to={-1}>Back</Link>
<Link to="/user/manager">Manager</Link>
<Link to="/user/manager" replace>Manager</Link>
<div>
}
Vue 中路由导航
<template>
<div>
<!-- 3. <Link> -->
<router-link to="/user/manager">Manager</router-link>
<router-link to="/user/manager" replace="true">Manager</router-link>
<div>
</template>
<script setup>
// 1. Router.navigate,这里的 router 即是上面创建的 Router 对象
router.navigate('/user/manager')
router.navigate('/user/manager', {replace: true})
router.navigate(-2)
router.back()
// 2. useNavigate
const navigate = useNavigate()
navigate('/user/manager')
navigate('/user/manager', {replace: true})
navigate(-2)
</script>
三、获取参数
React 中获取参数
import { useParams } from 'oh-router-react'
export const User = () => {
// 通过 useParams 获取参数
const params = useParams()
return <div>...<div>
}
Vue 中获取参数
setup 中
<script setup>
import { watch } from 'vue'
import { useParams } from 'oh-router-vue'
// 通过 useParams 获取参数
const params = useParams()
// 监听参数变化
watch(params, (newParams) => {
// do something
})
</script>
非 setup 中
<script>
export default {
created() {
// 通过 $location.params 获取参数
this.$location.params
// 监听参数变化
this.$watch(
() => this.$location.params,
() => {
// do something
}
)
},
}
</script>
四、嵌套路由
React 中使用嵌套路由
使用嵌套路由首先需要在配置路由时使用父子结构:
const router = new Router({
routes: [
{
path: '/',
element: <Layout />,
// 通过 children 定义父子结构路由
children:
{
path: '/users',
element: <UserManager />
},
{
path: '/books',
element: <BookManager />
},
]
},
],
})
最后在父路由组件中使用 <Outlet> 声明子路由出口
import { Outlet } from 'oh-router-react'
export default function Layout(){
return <div>
<NavBar/>
<Outlet />
<div>
}
这样就完成了,当我们访问 /users 时得到的页面结构:
<div>
<NavBar />
<UserManager />
</div>
这样就完成了,当我们访问 /books 时得到的页面结构:
<div>
<NavBar />
<BookManager />
</div>
Vue 中使用嵌套路由
和上面完全一样,只是 <Outlet> 注册成了全局组件,不需要导入,而且在 Vue 中使用时名字不一样:
<template>
<div>
<nav-bar />
<!-- 等效于 React 中的 <Outlet /> -->
<router-outlet />
</div>
</template>
五、路由中间件
路由中间件和 vue-router 中的路由守卫有点像,主要用来做一些页面权限验证,比如一个用户登陆验证的中间件:
import { Middleware } from 'oh-router'
import { router } from './router'
import store from 'src/store' // 我们假设用户信息在 store 中
export class MustLoginMiddleware extends Middleware {
handler = async (ctx, next) => {
if (store.user.hasLogin()) {
// 已登录则放行
await next()
} else {
// 没登陆前往登陆
router.navigate('/login')
}
}
// register 返回一个布尔值,为 true 则为当前导航的路由注册该中间件
register = ({ to }) => {
// 如果 pathname 不是 '/login' 则为当前路由注册该中间件
return to.pathname !== '/login'
}
}
还可以在配置路由时添加一些元数据,以便在中间件中访问,比如通过元数据声明路由允许哪些权限访问:
const router = new Router({
routes: [
{
path: '/user/manager',
element: <UserManager />
// 添加元数据
meta: {
role: ['superAdmin']
}
}
]
})
然后在权限验证的中间件中使用
import { Middleware } from 'oh-router'
import { router } from './router'
import store from 'src/store' // 我们假设用户信息在 store 中
export class RoleCheckMiddleware extends Middleware {
handler = async ({ to }, next) => {
if (to.meta.role!.indexOf(store.user.role) !== -1) {
// 用户权限在当前页面允许的权限内则放行
await next()
} else {
// 用户无权访问则弹窗警告并重定向到首页
alert('无权访问!')
router.navigate('/')
}
}
register = ({ to }) => {
// 如果 meta.role 存在的话则为当前路由注册该中间件
return !!to.meta.role
}
}
最后记得把这些中间件配置到路由中
const router = new Router({
routes: [
{
path: '/user/manager',
element: <UserManager />
// 添加元数据
meta: {
role: ['superAdmin']
}
}
],
// 配置中间件
middlewares: [
new MustLoginMiddleware(),
new RoleCheckMiddleware()
]
})
最后
一些使用示例: