Appearance
Vue 路由
一个页面装不下所有功能——文章列表、文章详情、发布表单、登录页,这些是不同的"页面"。在传统网站里每点一个链接就刷新整个页面、服务端返回新 HTML。Vue 做的是单页应用(SPA):页面不刷新,JS 在前端切换显示的内容。管理这种"页面切换"的工具叫路由。
一、安装 Vue Router
Vue Router 是 Vue 官方的路由库,需要在项目里额外安装:
bash
npm install vue-router@4二、定义路由
路由就是一张"地址 → 组件"的对照表。访问 /articles 时显示文章列表组件,访问 /articles/1 时显示详情组件:
text
src/
├── router/
│ └── index.js # 路由配置
├── views/ # 页面级组件放这
│ ├── ArticleList.vue
│ ├── ArticleDetail.vue
│ ├── ArticleForm.vue
│ └── Login.vue
└── main.js # 入口,挂载路由路由配置 src/router/index.js:
js
import { createRouter, createWebHistory } from "vue-router";
import ArticleList from "../views/ArticleList.vue";
import ArticleDetail from "../views/ArticleDetail.vue";
import ArticleForm from "../views/ArticleForm.vue";
import Login from "../views/Login.vue";
const routes = [
{ path: "/", redirect: "/articles" }, // 首页重定向到文章列表
{ path: "/articles", component: ArticleList }, // 文章列表
{ path: "/articles/:id", component: ArticleDetail }, // 文章详情(:id 是动态参数)
{ path: "/articles/new", component: ArticleForm }, // 新建文章
{ path: "/login", component: Login }, // 登录
];
const router = createRouter({
history: createWebHistory(), // 用 HTML5 History 模式,URL 里没有 #
routes,
});
export default router;每条路由是一个对象:path 是 URL 路径,component 是访问这个路径时显示的组件。/articles/:id 里的 :id 是动态参数——/articles/1、/articles/2 都匹配这条路由,id 分别是 1 和 2。
入口 src/main.js 里挂载路由:
js
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
createApp(App).use(router).mount("#app");三、路由出口和导航
<router-view> 是路由出口——当前路由匹配到的组件会显示在这个位置。<router-link> 是路由导航链接,点击后切换路由不刷新页面:
vue
<!-- App.vue -->
<template>
<nav>
<router-link to="/articles">文章列表</router-link>
<router-link to="/articles/new">写文章</router-link>
</nav>
<!-- 当前路由的组件显示在这 -->
<router-view />
</template><router-link to="/articles"> 渲染成一个 <a> 标签,点击后 URL 变成 /articles,<router-view> 里显示 ArticleList 组件。整个过程不刷新页面,所以不会闪一下白屏。
四、读取路由参数
详情页要拿到 URL 里的 id,用 useRoute:
vue
<!-- views/ArticleDetail.vue -->
<template>
<div v-if="loading">加载中...</div>
<div v-else-if="article">
<h2>{{ article.title }}</h2>
<p>{{ article.content }}</p>
</div>
<button @click="goBack">返回列表</button>
</template>
<script setup>
import { ref, onMounted } from "vue";
import { useRoute, useRouter } from "vue-router";
const route = useRoute(); // 读取当前路由信息
const router = useRouter(); // 编程式导航(跳页面)
const article = ref(null);
const loading = ref(true);
onMounted(async () => {
// route.params.id 拿到 URL 里的 :id 参数
const id = route.params.id;
console.log("加载文章 ID:", id);
// 实际场景:调后端接口
// article.value = await request(`/articles/${id}`);
// 模拟数据
article.value = { title: `文章 ${id}`, content: "这是正文内容。" };
loading.value = false;
});
function goBack() {
router.push("/articles"); // 编程式跳转,等价于点击 router-link to="/articles"
}
</script>useRoute() 返回当前路由信息,route.params.id 就是 URL 里 /articles/:id 的 id 部分。useRouter() 返回路由器实例,router.push() 是编程式导航——在代码里跳页面,不用用户点链接。
编程式导航的几种写法
js
const router = useRouter();
// 字符串路径
router.push("/articles");
// 对象写法,可以带参数
router.push({ path: `/articles/${id}` });
// 命名路由(路由配置里加了 name 时才能用)
router.push({ name: "articleDetail", params: { id: 1 } });
// 替换当前页面(不留历史记录,用户点后退回不到当前页)
router.replace("/login");
// 前进后退
router.back(); // 等价于浏览器的后退
router.forward(); // 等价于浏览器的前进五、导航守卫——登录拦截
有些页面需要登录才能访问。导航守卫在路由跳转前检查条件,不满足就拦截到登录页:
js
// router/index.js 末尾加
router.beforeEach((to, from) => {
const token = localStorage.getItem("access_token");
// 没登录且访问的不是登录页 → 跳到登录页
if (!token && to.path !== "/login") {
return "/login";
}
// 已登录还想去登录页 → 跳回首页
if (token && to.path === "/login") {
return "/articles";
}
// 其他情况正常放行(不 return 或 return true)
});beforeEach 在每次路由跳转前执行,参数是 to(目标路由)和 from(来源路由)。返回一个路径字符串表示重定向——返回 "/login" 就跳到登录页。不返回或返回 true 表示放行。
这是前端权限控制的基础——没 Token 的用户访问需要登录的页面,自动跳到登录页。注意这只是前端层面的检查,真正的权限验证在后端——前端拦住了体验更好,但后端接口也必须校验 Token,不能只靠前端。
六、完整页面结构
把这些合起来,一个带路由的文章管理应用结构大概是这样:
text
src/
├── router/
│ └── index.js # 路由配置 + 导航守卫
├── api/
│ └── client.js # fetch 封装(06 篇写的那个)
├── views/
│ ├── Login.vue # 登录页
│ ├── ArticleList.vue # 文章列表
│ ├── ArticleDetail.vue # 文章详情
│ └── ArticleForm.vue # 新建/编辑文章
├── components/
│ └── ArticleCard.vue # 可复用的文章卡片组件
├── App.vue # 根组件(导航栏 + router-view)
└── main.js # 入口views/放页面级组件(跟路由一一对应)components/放可复用的小组件(多处用的卡片、按钮、表单片段)api/放 fetch 封装和接口函数router/放路由配置和导航守卫
这个结构在后端基础篇的项目实战里会直接用——运维平台的前端就是同样的 views + components + api + router 四层,只是页面内容从文章管理换成了资产和任务管理。