Vue3 实战 - 配置路由
安装
shell
$ pnpm add vue-router
基本使用
定义路由
新建router/routes.ts
ts
const routes = [
{
path: "/index",
component: () => import("@/views/index.vue"), //路由懒加载
},
{
path: "/home",
component: () => import("@/views/home.vue"),
},
// Resolve refresh page, route warnings
{
path: "/:pathMatch(.*)*",
component: () => import("@/components/ErrorMessage/404.vue"),
},
];
export default routes;
创建路由实例
新建router/index.ts
ts
import { createRouter, createWebHistory } from "vue-router";
import routes from "./routes";
const router = createRouter({
history: createWebHistory(), //可传参数,配置base路径,例如'/app'
routes,
});
export default router;
注册路由
修改main.ts
ts
import router from "./router/index";
const app = createApp(App);
app.use(router); //注册路由
定义路由出口
修改 App.vue
vue
<template>
<router-view> App </router-view>
</template>
<style>
.fade-enter-active,
.fade-leave-active {
transition: all 0.2s ease;
}
.fade-enter-from,
.fade-leave-active {
opacity: 0;
}
</style>
router-view 将显示与 url 对应的组件,可以把它放在任何地方以适应布局。Transition 是基于路由的动态过渡动效
嵌套路由
在 App.vue 中定义的 router-view,这是顶层的出口,渲染最高级路由匹配到的组件。
如果要实现登录之后左侧菜单栏不变,右侧随路由的切换变化显示的内容,需使用嵌套路由。
定义路由
修改router/routes.ts
ts
import { RouteRecordRaw } from "vue-router";
/**
* 动态子路由
*/
export const dynamicRoutes: RouteRecordRaw[] = [
{
path: "/slide",
name: "slide",
component: () => import("@/views/slide/index.vue"),
meta: {
title: "演示文稿",
icon: "slide",
},
},
];
/**
* staticRouter: 静态路由
*/
export const staticRoutes: RouteRecordRaw[] = [
{
path: "/login",
name: "login",
component: () => import("@/views/login/index.vue"),
meta: {
title: "登录",
},
},
{
path: "/",
name: "layout",
component: () => import("@/layout/index.vue"),
children: [...dynamicRoutes],
},
];
/**
* errorRouter: 错误页面路由
*/
export const errorRoutes: RouteRecordRaw[] = [
{
path: "/403",
name: "403",
component: () => import("@/components/ErrorMessage/403.vue"),
meta: {
title: "403",
},
},
{
path: "/404",
name: "404",
component: () => import("@/components/ErrorMessage/404.vue"),
meta: {
title: "404",
},
},
{
path: "/500",
name: "500",
component: () => import("@/components/ErrorMessage/500.vue"),
meta: {
title: "500",
},
},
// Resolve refresh page, route warnings
{
path: "/:pathMatch(.*)*",
component: () => import("@/components/ErrorMessage/404.vue"),
},
];
路由实例
bash
import { createRouter, createWebHistory } from 'vue-router'
import { errorRoutes, staticRoutes } from './routes'
const router = createRouter({
history: createWebHistory(),
routes: [...staticRoutes, ...errorRoutes]
})
export default router
重定向
情景:在嵌套路由中,当访问/home时想重定向到/home/user
修改router/routes.ts
ts
{
path: '/home',
component: () => import('@/pages/home.vue'),
redirect: '/home/user', //新增
children: [
{
path: '/home/user',
component: () => import('@/pages/user.vue'),
},
{
path: '/home/manage',
component: () => import('@/pages/manage.vue'),
},
],
},
声明式、编程式导航
声明式导航
vue
<router-link to="/home"> 跳转home </router-link>;
编程式导航
ts
<script setup lang="ts">
import { useRouter } from 'vue-router';
const router = useRouter();
const handleManage = () => {
router.push('/home/manage');
};
</script>
路由参数
query 传参
vue
//页面传参
<script setup lang="ts">
import { useRouter } from 'vue-router';
const router = useRouter();
const handleManage = () => {
router.push({
path: '/home/manage',
query: {
plan: '123',
},
});
};
</script>
//页面接参
<script setup lang="ts">
import { useRoute } from 'vue-router';
const route = useRoute();
console.log(route.query.plan); //query接参
</script>
动态路由匹配
ts
//定义路由
{
path: '/register/:plan', // 动态字段以冒号开始
component: () => import('@/pages/register.vue'),
},
//页面传参
<script setup lang="ts">
import { useRouter } from 'vue-router';
const router = useRouter();
const handleManage = () => {
router.push('/register/123');
};
</script>
//页面接参
<script setup lang="ts">
import { useRoute } from 'vue-router';
const route = useRoute();
console.log(route.params.plan); //params接参
</script>
导航守卫
全局前置守卫
使用场景:做登录判断,未登陆用户跳转到登录页修改router/index.ts
router.beforeEach((to, from) => {
if (to.path === '/index') {
//在登录页做清除操作,如清除token等
}
if (!localStorage.getItem('token') && to.path !== '/index') {
// 未登陆且访问的不是登录页,重定向到登录页面
return '/index';
}
});
路由独享守卫
使用场景:部分页面不需要登录,部分页面需要登录才能访问
修改router/routes.ts
const auth = () => {
if (!localStorage.getItem("token")) {
// 未登陆,重定向到登录页面
return "/index";
}
};
const routes = [
...{
path: "/home",
component: () => import("@/pages/home.vue"),
redirect: "/home/user",
children: [
{
path: "/home/user",
component: () => import("@/pages/user.vue"),
},
{
path: "/home/manage",
component: () => import("@/pages/manage.vue"),
beforeEnter: auth, //路由独享守卫
},
],
},
];
组件内守卫
使用情景:预防用户在还未保存修改前突然离开。该导航可以通过返回 false 来取消
<script setup lang="ts">
import { onBeforeRouteLeave } from 'vue-router';
// 与 beforeRouteLeave 相同,无法访问 `this`
onBeforeRouteLeave((to, from) => {
const answer = window.confirm('确定离开吗');
// 取消导航并停留在同一页面上
if (!answer) return false;
});
</script>
路由元信息
将自定义信息附加到路由上,例如页面标题,是否需要权限,是否开启页面缓存等
使用情景:使用路由元信息+全局前置守卫实现部分页面不需要登录,部分页面需要登录才能访问
修改router/routes.ts
const routes = [
...{
path: "/home",
component: () => import("@/pages/home.vue"),
redirect: "/home/user",
children: [
{
path: "/home/user",
component: () => import("@/pages/user.vue"),
},
{
path: "/home/manage",
component: () => import("@/pages/manage.vue"),
meta: {
title: "管理页", // 页面标题
auth: true, //需要登录权限
},
},
],
},
];
修改router/index.ts
router.beforeEach((to, from) => {
if (!localStorage.getItem("token") && to.meta.auth) {
// 此路由需要授权,请检查是否已登录
// 如果没有,则重定向到登录页面
return {
path: "/index",
// 保存我们所在的位置,以便以后再来
query: { redirect: to.fullPath },
};
}
});