Vue Router 完整介绍与使用指南 – wiki大全

I apologize, but I made a mistake. I attempted to use a write_file tool which is not available in this environment. I will provide the article content directly in this response.

Here is a detailed article on Vue Router:

Vue Router 完整介绍与使用指南

Vue Router 是 Vue.js 官方的路由管理器。它与 Vue.js 深度集成,可以轻松构建单页面应用(Single Page Application, SPA)。通过 Vue Router,你可以将应用的 URL 地址与组件进行映射,从而实现无需刷新页面的路由切换,提升用户体验。

1. 为什么需要 Vue Router?

在传统的网页应用中,每次页面跳转都需要向服务器发送请求并重新加载整个页面。而单页面应用则不同,它在加载时只加载一次 HTML、CSS 和 JavaScript 文件,之后的所有页面切换都是通过 JavaScript 动态替换页面内容,这使得用户体验更加流畅,接近桌面应用。

Vue Router 的主要作用包括:
* 管理应用状态: URL 作为应用状态的一部分,Vue Router 可以帮助我们更好地管理和同步这种状态。
* 组件化视图: 将不同的路由映射到不同的 Vue 组件,使得应用结构更加清晰和模块化。
* 实现导航: 提供声明式和编程式的导航方式,方便用户在应用中切换视图。
* 处理页面切换逻辑: 通过导航守卫(Navigation Guards),可以在路由切换过程中执行权限验证、数据加载等逻辑。

2. 安装

首先,你需要有一个 Vue 项目。如果你还没有,可以使用 Vue CLI 创建一个:
bash
npm install -g @vue/cli
vue create my-vue-app
cd my-vue-app

安装 Vue Router:
“`bash
npm install vue-router@4 # Vue 3

或者 npm install vue-router@3 # Vue 2

“`
本文将主要以 Vue Router 4 (Vue 3) 为例进行介绍。

3. 基本用法

3.1 定义路由

路由是 URL 路径与组件的映射关系。在一个 router/index.js (或者其他你喜欢的文件) 中定义你的路由:

“`javascript
// router/index.js
import { createRouter, createWebHistory } from ‘vue-router’;
import Home from ‘../views/Home.vue’; // 你的 Home 组件
import About from ‘../views/About.vue’; // 你的 About 组件

const routes = [
{
path: ‘/’,
name: ‘Home’,
component: Home,
},
{
path: ‘/about’,
name: ‘About’,
component: About,
},
];
“`

3.2 创建路由器实例

使用 createRouter 函数创建路由器实例,并传入 routes 配置。同时,需要选择一种历史模式。
* createWebHistory():HTML5 History 模式,推荐使用,URL 不带 #。需要服务器端配置支持,以避免在直接访问深层路径时出现 404。
* createWebHashHistory():Hash 模式,URL 带 #,不需要服务器端特殊配置。
* createMemoryHistory():内存模式,不与 URL 交互,适用于 SSR 环境。

“`javascript
// router/index.js (续)
const router = createRouter({
history: createWebHistory(), // 或 createWebHashHistory()
routes,
});

export default router;
“`

3.3 注册到 Vue 应用

在你的 main.js (或 main.ts) 文件中将路由器实例注册到 Vue 应用:

“`javascript
// main.js
import { createApp } from ‘vue’;
import App from ‘./App.vue’;
import router from ‘./router’; // 导入路由器实例

createApp(App).use(router).mount(‘#app’);
“`

3.4 router-linkrouter-view

在你的根组件 App.vue 或其他组件中,使用 <router-link> 进行导航,使用 <router-view> 显示当前路由匹配的组件。

  • <router-link>:用于在应用中声明式地导航。它会被渲染成一个 <a> 标签,但当点击时,它会触发路由切换而不会重新加载页面。
    • to 属性:指定目标路由。
  • <router-view>:路由匹配到的组件将渲染在这里。

“`vue


“`

4. 动态路由匹配

很多时候,我们需要将某种模式匹配到的所有路由都映射到同一个组件。例如,一个用户资料页面,其 URL 可能是 /users/1/users/2 等。

4.1 路由参数

可以在 path 中使用动态片段来定义路由参数,用冒号 : 开头。

javascript
const routes = [
// ...
{
path: '/users/:id', // :id 是一个参数
name: 'UserDetail',
component: () => import('../views/UserDetail.vue'), // 懒加载组件
},
];

在组件中可以通过 $route.params 访问这些参数:

“`vue


“`

当参数变化时,UserDetail 组件会被复用,如果需要对参数变化做出响应,可以 watch $route.params.id 或使用 beforeRouteUpdate 导航守卫。

为了让组件更独立,可以将路由参数作为 props 传递给组件:

javascript
const routes = [
// ...
{
path: '/users/:id',
name: 'UserDetail',
component: () => import('../views/UserDetail.vue'),
props: true, // 将路由参数作为 props 传递
},
];

“`vue

“`

4.2 捕获所有路由或 404 Not Found 路由

使用 */:pathMatch(.*)* (Vue Router 4) 可以捕获所有未匹配的路由。通常用于 404 页面。

javascript
const routes = [
// ...
{
path: '/:pathMatch(.*)*', // 捕获所有路由
name: 'NotFound',
component: () => import('../views/NotFound.vue'),
},
];

注意:捕获所有路由的路由规则应该放在所有路由定义的最后,否则它会覆盖其他路由。

5. 嵌套路由

实际应用中,通常会遇到组件的层层嵌套。例如,一个用户详情页面可能包含用户个人信息、帖子、评论等子视图。

5.1 定义子路由

在父路由的 children 属性中定义子路由:

javascript
const routes = [
{
path: '/user/:id',
component: () => import('../views/User.vue'),
children: [
{
path: '', // 默认子路由,当访问 /user/:id 时显示
component: () => import('../views/UserProfile.vue'),
},
{
path: 'posts', // 访问 /user/:id/posts
component: () => import('../views/UserPosts.vue'),
},
{
path: 'comments', // 访问 /user/:id/comments
component: () => import('../views/UserComments.vue'),
},
],
},
];

5.2 嵌套 router-view

父组件 User.vue 中也需要一个 <router-view> 来渲染子路由匹配的组件:

“`vue


“`

6. 编程式导航

除了使用 <router-link> 进行声明式导航外,我们还可以通过 JavaScript 编程式地导航。

在组件内部,可以通过 this.$router 访问路由器实例。在 setup 函数中,可以使用 useRouter 钩子。

“`javascript
import { useRouter } from ‘vue-router’;

// …
setup() {
const router = useRouter();

const navigateToAbout = () => {
router.push(‘/about’);
};

const goBack = () => {
router.go(-1); // 后退一步
};

return {
navigateToAbout,
goBack,
};
}
“`

常用的方法有:
* router.push(location):向历史堆栈添加一个新条目,导航到新 URL。参数可以是字符串路径,也可以是路由地址对象。
javascript
router.push('/home');
router.push({ path: '/home' });
router.push({ name: 'UserDetail', params: { id: 123 } });
router.push({ path: '/register', query: { plan: 'premium' } });

* router.replace(location):与 push 类似,但它不会向历史堆栈添加新条目,而是替换当前条目。
javascript
router.replace('/home');

* router.go(n):在历史记录中前进或后退 n 步。
javascript
router.go(1); // 前进一步
router.go(-1); // 后退一步

7. 命名路由

给路由命名可以简化编程式导航和 <router-link> 的使用,尤其是当路由路径较长或需要动态生成时。

javascript
const routes = [
{
path: '/user/:id',
name: 'User', // 命名路由
component: () => import('../views/User.vue'),
},
];

使用命名路由进行导航:

“`vue

查看用户
“`

javascript
// 编程式导航
router.push({ name: 'User', params: { id: 123 } });

8. 命名视图

有时,你可能需要同时展示多个视图,而不是嵌套。例如,一个布局可能包含侧边栏、顶部导航和主内容区域,每个区域由不同的组件渲染。

javascript
const routes = [
{
path: '/',
components: { // 使用 components 替代 component
default: () => import('../views/Home.vue'), // 默认视图
sidebar: () => import('../components/Sidebar.vue'), // 命名为 sidebar 的视图
header: () => import('../components/Header.vue'), // 命名为 header 的视图
},
},
];

App.vue 中渲染命名视图:

“`vue


“`

9. 重定向和别名

9.1 重定向 (Redirect)

重定向是指当用户访问一个路径时,自动导航到另一个路径。

javascript
const routes = [
{
path: '/a',
redirect: '/b', // 当访问 /a 时,会自动重定向到 /b
},
{
path: '/c',
redirect: { name: 'Home' }, // 重定向到命名路由
},
{
path: '/d',
redirect: (to) => { // 动态重定向
// return { path: '/e' }
return '/e';
},
},
];

9.2 别名 (Alias)

别名允许你将一个路径作为另一个路径的替代。当用户访问别名路径时,URL 仍保持别名路径,但内容是目标路径的组件。

javascript
const routes = [
{
path: '/users/:id',
component: () => import('../views/User.vue'),
alias: '/people/:id', // /people/:id 是 /users/:id 的别名
},
];

现在,访问 /people/123 会渲染 User.vue 组件,但 URL 依然显示 /people/123

10. 导航守卫 (Navigation Guards)

导航守卫是 Vue Router 提供的钩子函数,用于在路由导航过程中执行一些逻辑,例如身份验证、数据获取、页面标题修改等。

导航守卫的执行顺序:
1. beforeEach (全局前置守卫)
2. beforeEnter (路由独享守卫)
3. beforeRouteEnter (组件内守卫,在组件创建前调用)
4. beforeRouteUpdate (组件内守卫,在当前路由改变,但该组件被复用时调用)
5. beforeRouteLeave (组件内守卫,在离开当前组件时调用)
6. beforeResolve (全局解析守卫)
7. afterEach (全局后置守卫)

10.1 全局前置守卫 (router.beforeEach)

在每次导航被确认前调用。常用于登录验证。

“`javascript
// router/index.js
router.beforeEach((to, from, next) => {
const isAuthenticated = localStorage.getItem(‘token’); // 假设通过 localStorage 判断登录状态

if (to.meta.requiresAuth && !isAuthenticated) {
// 如果路由需要认证但用户未登录,则重定向到登录页
next(‘/login’);
} else {
// 否则,允许导航继续
next();
}
});
``
*
to:目标路由对象。
*
from:当前路由对象。
*
next():必须调用,否则导航会被阻止。
*
next():进入下一个钩子。
*
next(false):终止当前导航。
*
next(‘/’)next({ path: ‘/’ }):重定向到一个新的路由。
*
next(error):导航中断,并将错误传递给router.onError()`。

10.2 全局解析守卫 (router.beforeResolve)

在所有组件内守卫和异步路由组件解析完成后,但在导航被确认之前调用。

javascript
router.beforeResolve(async (to, from, next) => {
// 可以在这里执行一些数据获取操作
if (to.meta.fetchData) {
// await fetchData();
}
next();
});

10.3 全局后置守卫 (router.afterEach)

在导航被确认后,组件渲染前调用。这些守卫不会接收 next() 函数,也不能改变导航本身。通常用于分析、修改页面标题等。

javascript
router.afterEach((to, from) => {
document.title = to.meta.title || 'My App';
});

10.4 路由独享守卫 (beforeEnter)

在路由配置中直接定义:

javascript
const routes = [
{
path: '/admin',
component: () => import('../views/Admin.vue'),
meta: { requiresAuth: true, roles: ['admin'] },
beforeEnter: (to, from, next) => {
// 检查用户角色
const userRole = localStorage.getItem('role');
if (to.meta.roles.includes(userRole)) {
next();
} else {
next('/forbidden');
}
},
},
可选的:添加一个 /forbidden 路由
{
path: '/forbidden',
name: 'Forbidden',
component: () => import('../views/Forbidden.vue'),
},
];

10.5 组件内守卫

  • beforeRouteEnter(to, from, next):在渲染该组件的对应路由被 confirm 前调用。在组件实例创建前调用,所以不能访问 this。可以通过 next(vm => { /* 访问 vm */ }) 来访问组件实例。
  • beforeRouteUpdate(to, from, next):在当前路由改变,但是该组件被复用时调用(例如,从 /users/1/users/2)。可以访问 this
  • beforeRouteLeave(to, from, next):在离开当前路由时调用。可以访问 this。常用于提示用户保存未保存的更改。

“`vue

“`

11. 路由元信息 (Meta Fields)

有时,你可能想给路由添加一些自定义的数据,例如 requiresAuthroles。这可以通过在路由配置中定义 meta 字段来实现。

javascript
const routes = [
{
path: '/dashboard',
component: () => import('../views/Dashboard.vue'),
meta: { requiresAuth: true, title: '控制台' }, // 添加元信息
},
{
path: '/login',
component: () => import('../views/Login.vue'),
meta: { public: true }, // 标记为公共路由
},
];

在导航守卫中访问元信息:

javascript
router.beforeEach((to, from, next) => {
if (to.meta.requiresAuth && !localStorage.getItem('token')) {
next('/login');
} else {
next();
}
});

12. 滚动行为 (Scroll Behavior)

当路由切换时,页面通常会滚动到顶部。Vue Router 允许你自定义滚动行为。

在创建路由器实例时配置 scrollBehavior

javascript
const router = createRouter({
history: createWebHistory(),
routes,
scrollBehavior(to, from, savedPosition) {
if (savedPosition) {
return savedPosition; // 如果有保存的滚动位置,则返回
} else {
// 始终滚动到顶部
return { top: 0, behavior: 'smooth' };
}
},
});

  • savedPosition:当使用浏览器前进/后退按钮时,这个 savedPosition 会被提供。
  • 返回 { top: 0 } 会滚动到页面顶部。
  • 返回 { selector: '#anchor' } 会滚动到指定元素。
  • 可以返回一个 Promise,延迟滚动。

13. 数据获取

在路由或组件渲染前获取数据通常有几种策略:

13.1 导航完成后获取 (推荐)

在组件的 mounted 钩子中获取数据。用户会先看到组件,再看到加载指示器,然后是获取到的数据。

“`vue

“`

13.2 导航进入前获取

可以在 beforeRouteEnterbeforeRouteUpdate 守卫中获取数据。这会确保数据在组件渲染前可用,但可能会导致导航延迟。

“`vue


“`

14. 路由模式 (History Modes)

14.1 Hash 模式 (createWebHashHistory)

使用 URL hash 值来模拟一个完整的 URL,因此当 URL 改变时,页面不会重新加载。例如 http://localhost:8080/#/about
* 优点:兼容性好,不需要服务器端配置。
* 缺点:URL 带有 #,不美观。

14.2 History 模式 (createWebHistory)

利用 HTML5 History API (pushStatereplaceStatepopstate 事件) 来实现 URL 跳转而无需重新加载页面。例如 http://localhost:8080/about
* 优点:URL 美观,与传统 URL 一致。
* 缺点:需要服务器端配置“回退”机制,以应对用户直接访问如 /about 这样的深层路径时,服务器能够正确地返回应用的主页(通常是 index.html),而不是 404。

服务器配置示例 (Nginx):
“`nginx
server {
listen 80;
server_name yourdomain.com;

location / {
root /path/to/your/dist;
index index.html;
try_files $uri $uri/ /index.html; # 关键配置
}
}
“`

15. 总结

Vue Router 是 Vue.js 应用中不可或缺的一部分,它提供了强大的路由功能,使得构建复杂的单页面应用变得轻松。通过掌握路由定义、导航方式、动态匹配、嵌套路由、导航守卫和滚动行为等核心概念,你可以高效地构建出用户体验优秀的 Vue.js 应用。在实际开发中,根据项目需求合理选择路由模式和数据获取策略,将有助于你构建健壮、高性能的单页面应用。

滚动至顶部