Vue3 vue-router

Vue3 vue-router

十二月 16, 2020

vue-router

安装

1
yarn add vue-router@4

打造路由实例

  1. 在 src 目录下新建 router,再新建 index.ts
  2. router/index.ts (step 1)
1
2
3
4
5
6
7
8
9
// index.ts

// step 1
// 引入createRouter
import { createRouter } from "vue-router";

const router = createRouter({});

export default router;
  1. 在 main.ts 中引入
1
2
import router from "./router";
createApp(App).use(router).mount("#app");
  1. 在 src 目录下新建 pages 文件夹,再新建一些即将打造的路由(home,application,cate,about,list,not-found),里面写组件

  2. createRouter() 中有两个参数

    1. history 用于选择路由模式
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    路由模式
    1. hash模式 比如: #/home
    - 兼容性强,ie/其他浏览器
    - 写法很别扭
    2. history模式 比如: /home
    - 新出的,基于html5做出来的,功能强大
    - 缺点
    - 看起来太像后端接口,所以一旦使用history模式就必须和后端配合使用
    - 这家伙看起来也像反向代理标识符,所以切记不能和反向代理标识符一致
    - 不兼容ie6-8
    1. routes 路由表
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
        用于确定一个路由对应一个组件
    {
    path: 路由路径 比如: /home
    component:路由渲染的组件
    meta 元数据 用于携带数据,比如做类似: 权限的功能
    redirect 重定向
    alias 别名【小名】
    children 子路由表 /home/hot
    beforeEnter 路由独享守卫,用于判断你是否有权限进入当前路由
    }


    component后面跟着的组件要使用路由懒加载
    1. 写法
    1. ()=> import() vue的异步组件
    2. /*webpackChunkName:'chunkName'*/ // webpack的代码分割功能
  3. router/index.ts (step 2)

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
59
60
61
62
63
64
65
66
67
68
// index.ts
// step 2
// 引入createWebHistory
import { createRouter, createWebHistory } from "vue-router";

const router = createRouter({
history: createWebHistory(),
routes: [
{
path: "/",
redirect: "/home", // 重定向到home
},
{
path: "/home",
component: () =>
import(/* webpackChunkName:"home" */ "../pages/home/index.vue"),
name: "home",
children: [
{
path: "/home/father",
component: () =>
import(/* webpackChunkName:"home" */ "../pages/home/far.vue"),
name: "father",
},
{
path: "/home/son",
component: () =>
import(/* webpackChunkName:"home" */ "../pages/home/son.vue"),
name: "son",
},
],
},
{
path: "/app",
component: () =>
import(/* webpackChunkName:"app1" */ "../pages/application/index.vue"),
name: "app",
},
{
path: "/cate",
component: () =>
import(/* webpackChunkName:"cate" */ "../pages/cate/index.vue"),
name: "cate",
},
{
path: "/about",
component: () =>
import(/* webpackChunkName:"about" */ "../pages/about/index.vue"),
name: "about",
},
{
path: "/list",
component: () =>
import(/* webpackChunkName:"list" */ "../pages/list/index.vue"),
name: "list",
},
{
path: "/:pathMatch(.*)*",
component: () =>
import(
/* webpackChunkName:"not-found" */ "../pages/not-found/index.vue"
),
name: "not-found",
},
],
});

export default router;

错误路由书写

1
2
3
4
5
{
path: '/:pathMatch(.*)*',
component: () => import(/* webpackChunkName:"not-found" */ '../pages/not-found/index.vue'),
name: 'not-found'
},

一级路由和路由嵌套

一级路由

  1. 在 App.vue 中
  2. 使用 router-link(这是导航)
  3. to(声明式跳转链接)
  4. 使用 router-view(这是视图)
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
<template>
<div>
<!-- 导航 -->
<div>
<ul class="app-nav-list">
<li><router-link to="/home"> home </router-link></li>
<li><router-link to="/app"> app </router-link></li>
<li><router-link to="/cate"> cate </router-link></li>
<li><router-link to="/about"> about </router-link></li>
<li><router-link to="/asd"> 404 </router-link></li>
</ul>
</div>
<!-- 视图 -->
<div>
<router-view></router-view>
</div>
</div>
</template>

<style lang="stylus">
.app-nav-list
display flex
justify-content space-evenly
width 500px
</style>

路由嵌套

  1. 在 src/pages/home/index.vue 中
  2. 路由表即 router 文件夹 index.ts 中 路由要写 children 等数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<template>
<div>
<h2>home</h2>
<router-link
:to="{
name: 'father',
}"
>father</router-link
>
<br />
<router-link
:to="{
name: 'son',
}"
>son</router-link
>
<hr />
<router-view></router-view>
</div>
</template>

路由监听

  1. 小案例 404 的时候上方导航不见
  2. 通过 navFlag 控制导航的销毁与创建
  3. 引入 useRoute 并实例化 const route = useRoute()
  4. watch(()=>route.path,()=>{对应的操作}) 来实现监听路由
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import { defineComponent, watch, reactive, toRefs } from "vue";
import { useRoute } from "vue-router";
export default defineComponent({
setup() {
const state = reactive({
navFlag: true,
});
const route = useRoute();
watch(
() => route.path,
() => {
if (route.matched[0].path === "/:pathMatch(.*)*") {
state.navFlag = false;
} else {
state.navFlag = true;
}
}
);
return {
...toRefs(state),
};
},
});

激活路由

  1. 在 router-link 标签中加 active-class 属性
  2. 切换的时候动态切换类名实现效果
1
2
3
<li>
<router-link active-class="active" to="/home"> home </router-link>
</li>

动态路由

  1. 什么是动态路由?
    1. url 是变化的,但是呢组件用的是同一个,这就是动态路由
  2. 动态传参
    1. 我们从一个组件中将数据携带在 url 上传递到另一个组件中去
  3. 动态接参
    1. 我们从 url 中获取参数,然后拿到参数之后进行使用【作为请求的参数】
  4. /about/index.vue 中 to 属性书写对象,name,params,query 属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!-- /about/index.vue -->
<template>
<div>
<div>about</div>
<router-link
:to="{
name: 'list',
params: {
id: 1,
},
query: {
a: 1,
b: 1,
title: '嘻嘻',
},
}"
>List</router-link
>
</div>
</template>
  1. to 中加了 params 中的 id 属性,所以要在 router 文件夹的 index 中编辑
1
2
3
4
5
{
path: '/list/:id', // 在list中加/:id
component: () => import(/* webpackChunkName:"list" */ '../pages/list/index.vue'),
name: 'list'
},
  1. 在 pages/list/index.vue 接收传过来的参数
  2. 从 vue-router 中引入 useRouter 并在 setup 中实例化
  3. 创建一个 reactive 数据接收参数
  4. 在挂载阶段,从 route.params 或者 route.query 中拿取数据赋值给 reactive 数据
  5. return
  6. 在 template 中使用数据
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
<template>
<div>
<div>list</div>
<p>{{ id }}</p>
<p>{{ a }}</p>
<p>{{ b }}</p>
<p>{{ title }}</p>
</div>
</template>

<script>
import { defineComponent, onMounted, reactive, toRefs } from "vue";
import { useRoute } from "vue-router";
export default defineComponent({
setup() {
const route = useRoute();
// console.log(route.params.id);
const state = reactive({
id: "0",
a: "",
b: "",
title: "",
});
onMounted(() => {
state.id = route.params.id;
state.a = route.query.a;
state.b = route.query.b;
state.title = route.query.title;
});
return {
...toRefs(state),
};
},
});
</script>

命令式跳转页面

  1. 从 vue-router 中引入 useRouter
  2. router 实例中有 push/replace 方法 里面写路径
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<template>
<div>
<div>cate</div>
<hr />

<button @click="toAbout">命令式toabout</button>
</div>
</template>

<script>
import { defineComponent } from "vue";
import { useRouter } from "vue-router";
export default defineComponent({
setup() {
const router = useRouter();
const toAbout = () => {
router.push("/about");
};
return {
toAbout,
};
},
});
</script>

路由的追加、删除、路由是否存在的判断

路由追加

  1. 引入 useRouter
  2. 使用实例 router.addRoute() 里面接收对象,之前怎么写路由就怎么写
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
<template>
<div>
<div>app</div>
<hr />
<button @click="add">路由追加</button>
<br />
<button @click="toNew">toNew</button>
</div>
</template>

<script>
import { defineComponent } from "vue";
import { useRouter } from "vue-router";
export default defineComponent({
setup() {
const router = useRouter();
// console.log(router);
const add = () => {
router.addRoute({
// 路由增加
path: "/new",
component: () =>
import(/* webpackChunkName:"new" */ "../new/index.vue"),
name: "new",
});
};
const toNew = () => {
router.push("/new");
};
return {
add,
toNew,
};
},
});
</script>

路由删除,路由判断

  1. router.removeRoute(‘RouterName’)
1
router.removeRoute("new");
  1. router.hasRoute(‘RouterName’)
1
router.hasRoute("new"); // 返回布尔值
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
<template>
<div>
<div>app</div>
<hr />
<button @click="add">路由追加</button>
<br />
<button @click="toNew">toNew</button>
<br />
<button @click="rm">删除new</button>
<br />
<button @click="has">判断是否有new</button>
</div>
</template>

<script>
import { defineComponent } from "vue";
import { useRouter } from "vue-router";
export default defineComponent({
setup() {
const router = useRouter();
// console.log(router);
const add = () => {
router.addRoute({
path: "/new",
component: () =>
import(/* webpackChunkName:"new" */ "../new/index.vue"),
name: "new",
});
};
const toNew = () => {
router.push("/new");
};
const rm = () => {
router.removeRoute("new");
};
const has = () => {
router.hasRoute("new") ? alert("yes") : alert("no");
};
return {
add,
toNew,
rm,
has,
};
},
});
</script>

过渡动效

  1. 安装
1
$ yarn add animate.css
  1. 全局引入,在 main.ts 书写
1
2
// main.ts
import "animate.css";
  1. 进入 App.vue
  2. 把之前的 router-view 组件用 transtion 组件包裹起来
  3. transtion 有三个属性
  4. mode
  5. enter-active-class
  6. leave-active-class
1
2
3
4
5
6
7
8
<!-- App.vue -->
<transition
mode="out-in"
enter-active-class="animate__animated animate__fadeInLeft"
leave-active-class="animate__animated animate__fadeOutLeft"
>
<router-view></router-view>
</transition>

路由元数据

  • 我们可以在 routes 中通过 meta 选项来携带一个数据,这个数据可以用来做很多事情,比如
    • 头部内容的变化
    • 面包屑导航
  1. 在 router 文件夹中修改 about 路由添加 meta 属性
1
2
3
4
5
6
7
8
{
path: '/about',
component: () => import(/* webpackChunkName:"about" */ '../pages/about/index.vue'),
name: 'about',
meta: { // 这是新增的
title: '这是关于页面'
}
},
  1. 进入 about 组件
  2. 引入 useroute
  3. route.meta.title 使用
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
<template>
<div>
<div>about</div>
<!-- 使用数据 -->
<h3>{{ title }}</h3>
<router-link
:to="{
name: 'list',
params: {
id: 1,
},
query: {
a: 1,
b: 1,
title: '嘻嘻',
},
}"
>List</router-link
>
</div>
</template>

<script>
import { defineComponent } from "vue";
import { useRoute } from "vue-router";
export default defineComponent({
setup() {
const route = useRoute();
return {
title: route.meta.title,
};
},
});
</script>

vue-router 中小 tips

  1. useRoute: 使用数据的时候用它
  2. useRouter: 使用方法的时候用它
  3. createRoute: 创建路由的时候用它

导航守卫

  1. 什么是导航守卫

    1. 导航守卫是 vue 提供的用于拦截路由的一种方式
    2. 类比: 停车场的那个起落杆/保安
  2. 导航守卫的类型

    1. 全局导航守卫【3】
      1. 全局前置守卫 beforeEach
      2. 全局解析守卫【用法类似全局前置守卫】 beforeResolve
      3. 全局后置守卫 afterEach
    2. 路由独享守卫【1】 beforeEnter
    3. 组件级守卫【3】
      1. 组件内前置守卫 beforeRouteEnter
      2. 组件内更新守卫 beforeRouteUpdate
      3. 组件内后置守卫 beforeRouteLeave
  3. 令牌: token

    1. token 的产生: 登录完成之后,后端会返回给我们
  4. 提供模拟数据的平台