按照官方文档的顺序来学习VueRouter:https://router.vuejs.org/zh

引入和基本使用

首先在使用vite构建的Vue项目中引入并使用Vue-Router。

  1. npm安装:npm install vue-router@4
  2. /src/components下创建两个组件Home.vueAbout.vue
  3. /src/router下创建index.js(路由配置单独放在这里比较好):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    import {createRouter, createWebHistory} from 'vue-router'

    // 导入组件
    import Home from '../components/Home.vue'
    import About from '../components/About.vue'

    // 定义路由表
    const routes = [
    {path: '/', component: Home},//组件不要带引号
    {path: '/about', component: About},
    ]

    // 创建路由实例
    const router = createRouter({
    history: createWebHistory(),
    routes,
    })

    // 最后需要导出,注意导出的语法
    export default router;
  4. main.js中引入/src/router/index.js并使用

    1
    2
    3
    4
    5
    6
    7
    8
    import { createApp } from 'vue'
    import './style.css'
    import App from './App.vue'
    import router from './router'// 自动定位到index.js

    const app = createApp(App)
    app.use(router)
    app.mount('#app')

加入路由组件后,我们将组件映射到路由上,这时就可以使用路由来访问组件。

但是不能通过直接访问链接看到组件,因为组件是不完整的。还需要把路由组件使用<router-view>挂载到根组件上才行。

1
2
3
4
5
6
7
8
<template>
<router-link to='/'>首页</router-link>&nbsp;
<router-link to='/about'>关于</router-link>
<h1>固定的头部</h1>
<!-- 访问对应路由对应的组件将渲染到这里 -->
<router-view></router-view>
<h1>固定的尾部</h1>
</template>
  1. 使用<router-view>将组件渲染出来。
  2. 使用<router-link>代替<a>标签,是的Vue Router在不重新加载页面的情况下修改URL,提高用户体验。

动态路由匹配

使用动态字段作为路径参数。比如,同一个User组件对不同的用户id渲染出不同的内容,这时候就可以用动态路由来匹配路径并获取到用户id。

1
2
3
4
5
// 路由表
const routes = [
// 动态字段以冒号开始
{ path: '/users/:id', component: User },
]

组件中可以使用$route.params来获取到动态匹配的参数:
1
2
3
4
5
<template>
<div style="background-color: yellow;">
{{$route.params.id}}的个人主页
</div>
</template>

Vue的动态字段比较类似Django的path转换器。

正则匹配

如果对于个人首页,既可以使用用户id匹配: /user/id,也可以使用用户名匹配: /user/uname,那么这时需要将两种匹配区分开。简单使用之前的动态参数是做不到的,还需要添加正则匹配。

1
2
3
4
const routes = [
{path: '/user/:id(\\d+)', component: User},
{path: '/user/:uname', component: User},
]

1
2
3
4
5
<template>
<div style="background-color: yellow;">
<h1>{{$route.params.id?('id为'+$route.params.id):('用户名为'+$route.params.uname)}}的个人主页</h1>
</div>
</template>

js的正则表达式需要转义斜杠,如\\d用于匹配数字。

image.png

添加404路由

如果url输入有误,那么就应该返回404页面。这时使用正则表达式添加一个匹配任意页面的路由来捕获没有和其他规则匹配到的路由。

1
2
3
const routes = [
{path: '/:pathMatch(.*)', component: NotFound},
]

这个路由规则也即使放在其他规则的前面,Vue也能正确匹配出其他页面,而不是显示404页面。

嵌套路由

官方文档上有一个嵌套路由很好的例子:个人主页。

1
2
3
4
5
6
7
8
 /user/sato               /user/sato/detail       /user/sato/posts
+------------------+ +-----------------+ +-----------------+
| sato | | sato | | sato |
| +--------------+ | | +-------------+ | | +-------------+ |
| | general | | -> | | detail | | -> | | posts | |
| | | | | | | | | | | |
| +--------------+ | | +-------------+ | | +-------------+ |
+------------------+ +-----------------+ +-----------------+

进入个人主页后显示基本信息,也可以切换到详细信息和发布的文章。generaldetailposts都是user的子组件。
子组件可以在路由表的children中注册。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 导入组件
const User = {
template: `
<h2>{{ $route.params.id }}的首页</h2>
<router-view></router-view>`,
}
// 配置路由表
const routes = [{
path: '/user/:id', component: User,
children: [
// 当 /user/:id 匹配成功
// UserHome 将被渲染到 User 的 <router-view> 内部
{ path: '', component: General },
{ path: 'detail', component: Detail },
{ path: 'posts', component: Posts },
// ...其他子路由
],
},
]

嵌套路由的子路由就不用加/了。

image.png

命名视图

如果想要同时展示多个视图,就需要用命名视图。比如常见的布局包括头部,主体和尾部,分别对应三个组件,且需要在一个页面上提示展示出它们。

  1. 注册路由时使用components注册多个组件。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    import Header from '../components/Header.vue'
    import Content from '../components/Content.vue'
    import Footer from '../components/Footer.vue'
    const routes = [
    {path: '/page/:id', components: {
    default: Content,
    Header, Footer, //键和值同名的简写
    }}
    ]
  2. 在根组件中使用带name<router-view>标签来展示相应组件。

image.png

导航守卫

导航守卫就是在跳转路由之前执行一系列操作。路由的导航守卫包括三种:全局、单个路由、组件级。

全局前置守卫

使用 router.beforeEach 注册一个全局前置守卫。beforeEach的参数是一个函数,函数的两个参数分别为tofrom

1
2
3
4
router.beforeEach((to, from) => {
console.log(to);
console.log(from);
})

这样每次跳转时就会打印出路由对象:
image.png

路由独享守卫

在路由表中添加beforeEnter

1
2
3
4
5
6
7
{
path: '/user/:uname', component: User,
beforeEnter: ((to, from) => {
console.log(to);
console.log(from);
})
},

使用这种路由独享的守卫比较好。

重定向与别名

重定向

如果想要//home/index都匹配到主页,那么可以注册三次,都对应Home组件:

1
2
3
4
5
const routes = [
{path: '/', component: Home},
{path: '/home', component: Home},
{path: '/index', component: Home},
}

这种做法最好使用路由重定向来替代:
1
2
3
4
5
const routes = [
{path: '/', component: Home},
{path: '/home', redirect: '/'},
{path: '/index', redirect: '/'},
}

使用重定向后如果访问/home会直接跳转到/。原理是当用户访问/home时,URL 会被/替换,然后匹配成/

别名

/别名为/home,意味着当用户访问/home时,URL 仍然是/home,但会被匹配为用户正在访问/

效果和为它们都配置component类似。

1
2
3
const routes = [
{path: '/', component: Home, alias: ['/home', '/index']},
}