Appearance
24|Vue 路由与导航守卫
单页应用(SPA)只有一个 HTML 页面,页面切换通过 JavaScript 替换内容实现,不需要整页刷新。Vue Router 是 Vue 官方的路由库,负责把 URL 映射到对应组件,管理浏览器历史记录,并提供导航守卫在路由切换前后执行逻辑。
一、安装和基本配置
bash
npm install vue-router@4js
// router/index.js
import { createRouter, createWebHistory } from "vue-router";
import ServerList from "../views/ServerList.vue";
import TaskList from "../views/TaskList.vue";
import Login from "../views/Login.vue";
const routes = [
{ path: "/", redirect: "/servers" },
{ path: "/login", component: Login },
{ path: "/servers", component: ServerList },
{ path: "/tasks", component: TaskList },
{ path: "/servers/:id", component: ServerDetail }, // 动态路由
];
const router = createRouter({
history: createWebHistory(),
routes,
});
export default router;js
// main.js
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
createApp(App).use(router).mount("#app");二、路由视图和链接
vue
<!-- App.vue -->
<template>
<nav>
<RouterLink to="/servers">服务器</RouterLink>
<RouterLink to="/tasks">任务</RouterLink>
</nav>
<!-- 当前路由对应的组件渲染在这里 -->
<RouterView />
</template>| 组件 | 作用 |
|---|---|
RouterLink | 生成路由链接,点击不会刷新页面 |
RouterView | 占位符,显示当前路由匹配的组件 |
RouterLink 渲染为 a 标签,但会拦截点击事件,用 JavaScript 切换路由。
激活状态样式
vue
<RouterLink to="/servers" active-class="active-link">服务器</RouterLink>当前路由匹配时,会自动添加 active-class 指定的类名。
三、动态路由
js
const routes = [
{ path: "/servers/:id", component: ServerDetail },
];:id 是路由参数,可以匹配 /servers/1、/servers/web-01 等路径。
在组件中读取参数:
vue
<script setup>
import { useRoute } from "vue-router";
const route = useRoute();
console.log(route.params.id); // "1" 或 "web-01"
</script>查询参数
js
// URL: /servers?page=2&limit=20
console.log(route.query.page); // "2"
console.log(route.query.limit); // "20"查询参数都是字符串,需要数字时手动转换:
js
const page = Number(route.query.page) || 1;四、编程导航
除了在模板中用 RouterLink,也可以在 JavaScript 中跳转:
vue
<script setup>
import { useRouter } from "vue-router";
const router = useRouter();
function goToDetail(id) {
router.push(`/servers/${id}`);
}
function goBack() {
router.back();
}
</script>| 方法 | 作用 |
|---|---|
router.push(path) | 跳转到新路由(加入历史栈) |
router.replace(path) | 替换当前路由(不加入历史栈) |
router.back() | 后退 |
router.go(n) | 前进/后退 n 步 |
五、导航守卫
在路由切换前后执行校验或准备工作:
全局前置守卫
js
// router/index.js
import { useUserStore } from "../stores/user.js";
router.beforeEach((to, from, next) => {
const user = useUserStore();
// 需要登录但未登录,重定向到登录页
if (to.meta.requiresAuth && !user.isLoggedIn) {
next("/login");
} else {
next(); // 放行
}
});| 参数 | 含义 |
|---|---|
to | 即将进入的目标路由 |
from | 当前正要离开的路由 |
next() | 放行;next("/login") 重定向;next(false) 取消导航 |
路由元信息
在路由配置中标记额外信息:
js
const routes = [
{
path: "/servers",
component: ServerList,
meta: { requiresAuth: true, title: "服务器列表" },
},
];组件内守卫
vue
<script setup>
import { onBeforeRouteLeave, onBeforeRouteUpdate } from "vue-router";
// 离开当前页面前
onBeforeRouteLeave((to, from, next) => {
if (hasUnsavedChanges.value) {
const confirmed = confirm("有未保存的更改,确定离开?");
next(confirmed);
} else {
next();
}
});
// 当前路由参数变化时(如从 /servers/1 到 /servers/2)
onBeforeRouteUpdate((to, from) => {
loadServerDetail(to.params.id);
});
</script>六、懒加载
大型应用中,把所有组件打包成一个文件会导致首屏加载慢。路由懒加载让组件只在进入对应路由时才下载:
js
const routes = [
{
path: "/servers",
component: () => import("../views/ServerList.vue"),
},
];import() 返回 Promise,Vue Router 在需要时自动等待组件加载完成。
七、常见错误
在 setup 之外使用 useRoute / useRouter
js
// 错误:必须在组件的 setup 期间调用
const route = useRoute();
// 正确
export default {
setup() {
const route = useRoute(); // OK
},
};导航守卫中忘记调用 next
js
router.beforeEach((to, from, next) => {
if (to.meta.requiresAuth && !isLoggedIn) {
next("/login");
}
// 错误:未登录时 else 分支没有 next(),导航卡住
});动态路由参数变化时组件不复用
js
// 从 /servers/1 跳转到 /servers/2,默认复用组件,不重新挂载
// 需要监听路由变化
import { watch } from "vue";
import { useRoute } from "vue-router";
const route = useRoute();
watch(() => route.params.id, (newId) => {
loadDetail(newId);
}, { immediate: true });或者用 onBeforeRouteUpdate 组件守卫。