创建 vue 应用的路由器

路由可以让用户在访问某个特定地址的时候,显示应用里的某一个特定的组件。在 vue 中使用路由的时候需要安装一个包,在 package.json 中的 dependencies 里可以添加一个依赖 “vue-router”:”^4.0.0-0”

新建文件 app/app.router.ts

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

/**
* 定义路由
*/
const routes: Array<RouteRecordRaw> = [];

/**
* 创建路由器
*/
const router = createRouter({
history: createWebHistory(),
routes,
});

export default router;

创建完成后需要在 vue 应用里用一下,打开入口文件 main.ts:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { createApp } from 'vue';
import App from './app/app.vue';
import appRouter from './app/app.router';

/**
* 创建应用
*/
const app = createApp(App);

/**
* 应用路由
*/
app.use(appRouter);

/**
* 挂载应用
*/
app.mount('#app');

这样就完成了路由的创建。


定义 vue 应用的路由

定义路由其实就是设置一下这个路由的地址,还有对应的组件,举个栗子,新建组件 components/index.vue、 components/about.vue
index.vue:

1
2
3
<template>
<div>你好,欢迎你</div>
</template>

about.vue:

1
2
3
<template>
<div>这里是侏罗纪公园</div>
</template>

打开 app.router.ts,引入刚才创建的组件,配置路由。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
import Index from './components/index.vue';
import About from './components/about.vue';

/**
* 定义路由
*/
const routes: Array<RouteRecordRaw> = [
{
path: '/',
component: Index,
},
{
path: '/about',
component: About,
},
];

/**
* 创建路由器
*/
const router = createRouter({
history: createWebHistory(),
routes,
});

export default router;

在 app.vue 中添加路由显示的标签:

1
2
3
<template>
<router-view></router-view>
</template>

然后去浏览器访问 http://localhost:8080 会发现打开了 index 这个组件,http://localhost:8080/about 会打开 about 组件。


使用 to 属性来设置跳转路径。

1
2
<router-link class="menu-item" to="/">首页</router-link>
<router-link class="menu-item" to="/about">关于</router-link>

用代码切换路由地址 ($router.push与$router.replace)

$router.push 会添加新的浏览历史,$router.replace 会替换掉当前的浏览历史。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<template>
<div @click="onClickText">你好,欢迎你</div>
</template>

<script>
export default {
methods: {
onClickText() {
// this.$router.push('/about');
this.$router.replace('/about');
},
},
};
</script>

给路由起个名字

app.router.ts:

1
2
3
4
5
{
path: '/about',
name: 'about',
component: About,
}

在 app.vue 中就可以使用定义的 name 来进行跳转了,绑定 to 属性,值是一个对象,声明一下要跳转的组件的 name

1
2
3
<router-link class="menu-item" :to="{ name: 'about' }"
>关于</router-link
>

重定向

用 redirect 配置重定向,三种方法皆可,使用函数的话可以先进行处理再重定向,比如要判断用户重定向到哪。

1
2
3
4
5
6
7
8
9
{
path: '/about-us',
// redirect: '/about',
// redirect: { name: 'about' },
redirect: to => {
console.log(to);
return '/about';
},
}

路由模块

应用的路由可以在不同的模块里去定义,然后在应用的路由器模块里去导入这些路由模块,再把定义的路由交给路由器里的 routes 属性就行了。举个栗子,新建组件 post/index/post-index.vue,新建路由模块 post/post.routes.ts
post-index.vue:

1
2
3
<template>
<div>PostIndex</div>
</template>

post/post.routes.ts:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { RouteRecordRaw } from 'vue-router';
import PostIndex from './index/post-index.vue';

/**
* 定义路由
*/
const routes: Array<RouteRecordRaw> = [
{
path: '/posts',
name: 'postIndex',
component: PostIndex,
},
];

export default routes;

模块路由定义好了,去路由器文件中引入配置一下,app.router.ts:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
import Index from './components/index.vue';
import About from './components/about.vue';
import postRoutes from '@/post/post.routes'; //这里引入,@表示src目录
/**
* 定义路由
*/
const routes: Array<RouteRecordRaw> = [
{
path: '/',
component: Index,
},
{
path: '/about',
name: 'about',
component: About,
},
{
path: '/about-us',
// redirect: '/about',
// redirect: { name: 'about' },
redirect: to => {
console.log(to);
return '/about';
},
},
...postRoutes, //在这里配置,使用...
];

/**
* 创建路由器
*/
const router = createRouter({
history: createWebHistory(),
routes,
});

export default router;

配置完成后,在 app.vue 中就可以使用了:

1
2
3
<router-link class="menu-item" :to="{ name: 'postIndex' }"
>内容</router-link
>

动态路由

在访问地址中设置参数,定义一个动态路由,举个栗子,新建组件 post/show/post-show.vue

1
2
3
4
5
6
7
8
9
10
11
<template>
<div>PostShow {{ $route.params.postId }}</div> //获取地址参数 postId
</template>

<script>
export default {
created() {
console.log(this.$route.params.postId); //打印地址参数 postId
},
};
</script>

配置路由模块,post.routes.ts:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import { RouteRecordRaw } from 'vue-router';
import PostIndex from './index/post-index.vue';
import PostShow from './show/post-show.vue'; //引入组件

/**
* 定义路由
*/
const routes: Array<RouteRecordRaw> = [
{
path: '/posts',
name: 'postIndex',
component: PostIndex,
},
{
path: '/posts/:postId', //设置地址参数 postId
name: 'postShow',
component: PostShow,
},
];

export default routes;

嵌套路由

嵌套路由就是在一个路由里面可以定义一些子路由,子路由的定义方法和其他路由一样。举个栗子,新建组件 post/show/components/post-meta.vue:

1
2
3
<template>
<div>PostMeta</div>
</template>

在模块路由 post.routers.ts 中配置一下子路由:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import { RouteRecordRaw } from 'vue-router';
import component from './index/post-index.vue';
import PostIndex from './index/post-index.vue';
import PostShow from './show/post-show.vue';
import PostMeta from './show/components/post-meta.vue';

/**
* 定义路由
*/
const routes: Array<RouteRecordRaw> = [
{
path: '/posts',
name: 'postIndex',
component: PostIndex,
},
{
path: '/posts/:postId',
name: 'postShow',
component: PostShow,
children: [ //配置子路由,使用children属性,值是个数组
{
path: 'meta', //子路由地址
component: PostMeta, //子路由组件
},
],
},
];

export default routes;

最后别忘了给父组件添加一个 router-view 标签,否则子路由没有地方显示。post-show-vue:

1
2
3
4
5
6
7
8
9
10
11
12
<template>
<div>PostShow {{ $route.params.postId }}</div>
<router-view></router-view> //给子路由显示的位置
</template>

<script>
export default {
created() {
console.log(this.$route.params.postId);
},
};
</script>

访问 http://localhost:8080/posts/4/meta 已经可以看到配置的子路由里的内容了。


给路由组件传递属性

在路由定义那里可以直接给路由组件传递属性。也可以把地址参数的值转换成组件里面的属性然后交给路由组件。举个栗子,在 post.routes.vue 中配置一下模块路由:

1
2
3
4
5
6
7
8
9
10
11
12
{
path: '/posts/:postId',
name: 'postShow',
component: PostShow,
props: true, //这里将props设置为true
children: [
{
path: 'meta',
component: PostMeta,
},
],
},

然后打开 post-show.vue:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<div>PostShow {{ postId }}</div>
<router-view></router-view>
</template>

<script>
export default {
props: { //这里设置一下props
postId: String, //这个值要和地址参数的一样
},
created() {
console.log(this.$route.params.postId);
},
};
</script>

如果你想给路由组件传递一些静态的值的话,可以这样,打开 post.routes.ts:

1
2
3
4
5
6
7
8
{
path: '/posts',
name: 'postIndex',
component: PostIndex,
props: { //注意这里是个对象
sort: 'popular', //传递一个sort,值是一个字符串
},
},

打开 post-index.vue:

1
2
3
4
5
6
7
8
9
10
11
<template>
<div>PostIndex {{ sort }}</div> //输出sort
</template>

<script>
export default {
props: { //在这里配置props
sort: String,
},
};
</script>

导航守卫

在切换路由地址的时候可以安排一些导航守卫去做一些检查,在导航守卫里面我们可以获取到用户要访问的那个路由,还有用户来自哪里。比如用户在访问个人档案页面的时候你可以在守卫里去判断当前用户是否登录了。导航守卫可以安排在应用的全局,也可以放在具体的某一个路由里面,还可以放在某一个路由组件里。下面在应用的全局添加一个导航守卫,这样每一次导航都会经过这个守卫的检查。打开 app.router.ts:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
import Index from './components/index.vue';
import About from './components/about.vue';
import postRoutes from '@/post/post.routes';
/**
* 定义路由
*/
const routes: Array<RouteRecordRaw> = [
{
path: '/',
component: Index,
},
{
path: '/about',
name: 'about',
component: About,
},
{
path: '/about-us',
// redirect: '/about',
// redirect: { name: 'about' },
redirect: to => {
console.log(to);
return '/about';
},
},
...postRoutes,
];

/**
* 创建路由器
*/
const router = createRouter({
history: createWebHistory(),
routes,
});

/**
* 导航守卫
*/
router.beforeEach((to, from, next) => {
//to 就是用户要访问的路由
//from 是用户来自哪个路由
//next 是个函数,在导航守卫里面要执行这个函数才能够完成导航

console.log('to:', to);
console.log('from:', from);

if (to.name === 'postIndex') {
next('/');
} else {
next();
}
});

export default router;

路由元数据字段

在定义路由的时候可以在上面添加一些元数据来描述一下这条路由,你可以利用这些元数据去做一些事情,比如在应用里面有一些路由需要检查用户的登录状态,有一些不需要检查,你可以在需要检查登录状态的路由上面添加一个元数据说明一下这条路由需要检查用户的登录状态,然后在导航守卫里可以检查路由的元数据,如果需要检查用户登录状态,用户暂时没有登录,就可以把用户带到登录页面上。举个栗子,打开 app.router.ts:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
import Index from './components/index.vue';
import About from './components/about.vue';
import postRoutes from '@/post/post.routes';
/**
* 定义路由
*/
const routes: Array<RouteRecordRaw> = [
{
path: '/',
component: Index,
},
{
path: '/about',
name: 'about',
component: About,
meta: { //定义元数据,将requiresAuth设置为true,然后在导航守卫中处理
requiresAuth: true,
},
},
{
path: '/about-us',
// redirect: '/about',
// redirect: { name: 'about' },
redirect: to => {
console.log(to);
return '/about';
},
},
...postRoutes,
];

/**
* 创建路由器
*/
const router = createRouter({
history: createWebHistory(),
routes,
});

/**
* 导航守卫
*/
router.beforeEach((to, from, next) => {
//to 就是用户要访问的路由
//from 是用户来自哪个路由
//next 是个函数,在导航守卫里面要执行这个函数才能够完成导航

//matched表示匹配的路由,因为我们可以定义嵌套路由,所以可能会有多条路由匹配,这个metched就是匹配的所有路由,值应该是一个数组。
const requiresAuth = to.matched.some(record => record.meta.requiresAuth); //意思是 如果被匹配的路由里面有没有元数据里面的requiresAuth这个数据的值是true的记录,如果有,requiresAuth的值就会是true,没有就是false

if (requiresAuth) {
console.log(`requiresAuth为:${requiresAuth}`);
}
next();
});

export default router;

这时在访问 about 这个地址的时候,就会在控制台打印出结果了。