avatar

Vue-5-VueRouter

什么是路由

阶段

后端路由阶段

前端路由阶段

改变URL页面不刷新

URL的hash

HTML5的history模式: pushState

HTML5的history模式: replaceState

HTML5的history模式: go

认识vue-router

安装和使用

在初始化项目的时候可以选择安装vue-router,或者 vue ui添加

初步使用

搭建框架

main.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import Vue from 'vue'
import App from './App'
// 自动取找 ./router/index.js 所以不写 index.js 也行
import router from './router'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
el: '#app',
// 字面量增强写法,相当于 router: router
router,
render: h => h(App)
})

项目构建完成后,打开 rouer 文件夹

index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 配置路由相关的信息
import VueRouter from 'vue-router'
import Vue from 'vue'


// 1、通过Vue.use(插件),安装插件
Vue.use(VueRouter)

// 2、创建VueRouter对象
const routes = [

]
const router = new VueRouter({
// 配置路由和组件之间的应用关系
routes
})

// 3、将router对象传入到Vue实例
export default router

components 文件夹下创建修改文件

Home.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<template>
<div>
<h2>我是首页</h2>
<p>我是首页内容</p>
</div>
</template>

<script>
export default {
name: "Home"
}
</script>

<style scoped>

</style>

About.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<template>
<div>
<h2>我是关于</h2>
<p>我是关于内容</p>
</div>
</template>

<script>
export default {
name: "About"
}
</script>

<style scoped>

</style>

router 文件夹下 index.js

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
// 配置路由相关的信息
import VueRouter from 'vue-router'
import Vue from 'vue'

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


// 1、通过Vue.use(插件),安装插件
Vue.use(VueRouter)

// 2、创建VueRouter对象
const routes = [
{
path: '/home',
component: Home
},
{
path: '/about',
component: About
}
]
const router = new VueRouter({
// 配置路由和组件之间的应用关系
routes
})

// 3、将router对象传入到Vue实例
export default router

修改 App.vue

router-line 和 router-view
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<template>
<div id="app">
<router-link to="/home">首页</router-link>
<router-link to="/about">关于</router-link>
<!--占位 点击某个 router-link 的时候会将返回的数据填充到 router-view-->
<router-view></router-view>
</div>
</template>

<script>
export default {
name: 'App'
}
</script>

<style>
</style>

浏览器访问效果

点击哪儿,显示哪个组件的数据,并且浏览器不会刷新

路由的默认路径

修改 history 模式

默认的路径是一个 hash 值,不好看

修改成 history 模式

index.js文件中添加

1
2
3
4
5
6
const router = new VueRouter({
// 配置路由和组件之间的应用关系
routes,
// 修改路径模式为 history
mode: 'history'
})

router-link 的其他属性

tag

router-link 默认渲染的是一个 a 标签,我们也可以自定义想要渲染的标签

1
2
// tag 自定义渲染的标签
<router-link to="/home" tag="button">首页</router-link>

replace

点击一个页面后不能后退

1
<router-link to="/home" tag="button" replace>首页</router-link>

active-class

比如说:当这个按钮处于活跃状态,也就是被点击的时候,会默认给这个按钮加上class,那么我们就可以根据这个class,自定义样式

App.vue

1
2
3
4
5
<style>
.router-link-active {
color: red;
}
</style>

效果

自定义 class 名字 linkActiveClass

1
<router-link to="/home" tag="button" replace active-class="active">首页</router-link>

简便写法

在路由里添加,index.js

1
2
3
4
5
6
7
8
const router = new VueRouter({
// 配置路由和组件之间的应用关系
routes,
// 修改路径模式为 history
mode: 'history',
// 修改class名
linkActiveClass: 'active'
})

路由代码跳转

this.$router.push()

this.$router.replace()

App.vue

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
<template>
<div id="app">
<button @click="homeClick">首页</button>
<button @click="aboutClick">关于</button>
<!--占位 点击某个 router-link 的时候会将返回的数据填充到 router-view-->
<router-view></router-view>
</div>
</template>

<script>
export default {
name: 'App',
methods: {
homeClick() {
// 通过代码的方式修改 路由 vue-router
// this.$router.push('/home').catch(err => {err})
this.$router.replace('/home').catch(err => {err})
console.log('homeClick');
},
aboutClick() {
// this.$router.push('/about').catch(err => {err})
this.$router.replace('/about').catch(err => {err})
console.log('aboutClick');
}
}
}
</script>

动态路由

路径中动态显示信息

创建 User.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<template>
<div>
<h2>我是用户界面</h2>
<p>我是用户的相关信息</p>
</div>
</template>

<script>
export default {
name: "User"
}
</script>

<style scoped>

</style>

index.js 导入 User.vue

1
import User from '../components/User'

添加路由映射关系

1
2
3
4
{
path: '/user/:userId',
component: User
}

App.vue

1
2
// 使用 v-bind 简写 : 动态绑定 userId
<router-link :to="'/user/'+userId" replace>用户</router-link>
1
2
3
4
5
6
7
8
9
10
<script>
export default {
name: 'App',
data(){
return{
userId: 'lisi'
}
}
}
</script>

效果

页面中动态显示信息

User.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<template>
<div>
<h2>我是用户界面</h2>
<p>我是用户的相关信息</p>
<h2>{{userId}}</h2>
</div>
</template>

<script>
export default {
name: "User",
computed: {
userId() {
return this.$route.params.userId
}
}
}
</script>

<style scoped>

</style>

或者可以

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<template>
<div>
<h2>我是用户界面</h2>
<p>我是用户的相关信息</p>
<h2>{{$route.params.userId}}</h2>
</div>
</template>

<script>
export default {
name: "User"
}
</script>

<style scoped>

</style>

效果

$router 是整个路由的实例,也就是index.js里的 const router = new VueRouter

$route 是哪个组件处于活跃状态就拿到哪个组件

路由的懒加载

路由懒加载的效果

懒加载的方式

使用第三种方式

修改index.js 导入组件的方式

1
2
3
4
// 懒加载方式
const Home = () => import('../components/Home')
const About = () => import('../components/About')
const User = () => import('../components/User')

打包查看效果

一个懒加载对应一个 js 文件,用户访问的时候请求对应的js文件,减轻压力

路由的嵌套使用

创建页面

创建 Home.vue 的子组件 HomeNews.vue 和 HomeMessage.vue

HomeNews.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<template>
<div>
<ul>
<li>新闻1</li>
<li>新闻2</li>
<li>新闻3</li>
<li>新闻4</li>
</ul>
</div>
</template>

<script>
export default {
name: "HomeNews"
}
</script>

<style scoped>

</style>

HomeMessage.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<template>
<div>
<ul>
<li>消息1</li>
<li>消息2</li>
<li>消息3</li>
<li>消息4</li>
</ul>
</div>
</template>

<script>
export default {
name: "HomeMessage"
}
</script>

<style scoped>

</style>

使用

index.js

导入

1
2
const HomeNews = () => import('../components/HomeNews')
const HomeMessage = () => import('../components/HomeMessage')

嵌套进 Home

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const routes = [
{
path: '/home',
component: Home,
children: [
{
// 进入 /home时的默认路径
path: '',
redirect: 'news'
},
{
path: 'news',
component: HomeNews
},
{
path: 'message',
component: HomeMessage
}
]
}
]

Home.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<template>
<div>
<h2>我是首页</h2>
<p>我是首页内容</p>
<router-link to="/home/news">新闻</router-link>
<router-link to="/home/message">消息</router-link>
<router-view></router-view>
</div>
</template>

<script>
export default {
name: "Home"
}
</script>

<style scoped>

</style>

效果

路由的参数传递

方式1:params

点击前往

方式2:query

创建 Profile.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<div>
<h2>我是Profile组件</h2>
</div>
</template>

<script>
export default {
name: "Profile"
}
</script>

<style scoped>

</style>

index.js添加路由映射

1
2
3
4
{
path: '/profile',
component: Profile
}

使用 query 的方式传参

App.vue

1
<router-link :to="{path: '/profile',query: {name: 'duxiu',age: 18,height: 188}}" replace>档案</router-link>

Profile.vue 接收

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<template>
<div>
<h2>我是Profile组件</h2>
<h2>{{$route.query}}</h2>
<h2>{{$route.query.name}}</h2>
<h2>{{$route.query.age}}</h2>
<h2>{{$route.query.height}}</h2>
</div>
</template>

<script>
export default {
name: "Profile"
}
</script>

<style scoped>

</style>

效果

App.vue

1
<button @click="profileClick">档案</button>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<script>
export default {
name: 'App',
data(){
return{
userId: 'lisi'
}
},
methods: {
profileClick(){
this.$router.push({
path: '/profile',
query: {
name: 'aaa',
age: 20,
height: 188
}
}).catch(err => {err})
}
}
}
</script>

效果是一样的

导航守卫

为什么使用?

beforeEach

App.vue routes数组中添加 meta 元数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const routes = [
{
// 默认值
path: '',
// 重定向
redirect: '/home'
},
{
path: '/home',
component: Home,
// 元数据
meta: {
title: '首页'
}
}
]

router 实例同级添加如下代码

1
2
3
4
5
6
// 前置钩子(hook)
router.beforeEach((to, from, next) => {
// 从from跳转到to,获得到活跃组件的元数据中的title
document.title = to.matched[0].meta.title
next()
})

效果

afterEach

后置钩子

1
2
3
4
// 后置钩子
router.afterEach((to, from) => {
console.log('-----------------------------')
})

上述的是全局守卫,除了全局还有组件守卫,路由独享守卫

官网https://router.vuejs.org/zh/guide/advanced/navigation-guards.html#%E8%B7%AF%E7%94%B1%E7%8B%AC%E4%BA%AB%E7%9A%84%E5%AE%88%E5%8D%AB

keep-alive 遇见 vue-router

组件不会被频繁的创建和修改

没有使用 keep-alive

Home.vue export default{} 添加 函数

1
2
3
4
5
6
7
8
// 创建时
created() {
console.log('Home created');
},
// 销毁时
destroyed() {
console.log('Home destroyed');
}

效果

使用 keep-alive

App.vue 添加

1
2
3
4
// 在 <router-view></router-view> 外面包一层 keep-lived
<keep-alive>
<router-view></router-view>
</keep-alive>

效果

通过 keep-alive 实现导航记录

index.js

把 home 的 news 默认路径注释掉

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
path: '/home',
component: Home,
// 元数据
meta: {
title: '首页'
},
children: [
/*{
// 进入 /home时的默认路径
path: '',
redirect: 'news'
},*/
{
path: 'news',
component: HomeNews
},
{
path: 'message',
component: HomeMessage
}
]
}

App.vue

1
2
3
4
5
6
7
8
<template>
<!--占位 点击某个 router-link 的时候会将返回的数据填充到 router-view-->
<keep-alive>
<router-view></router-view>
</keep-alive>

</div>
</template>

Home.vue

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>
<h2>我是首页</h2>
<p>我是首页内容</p>
<router-link to="/home/news">新闻</router-link>
<router-link to="/home/message">消息</router-link>
<router-view></router-view>
</div>
</template>

<script>
export default {
name: "Home",
data(){
return {
path: '/home/news'
}
},
// 活跃时调用
// 使用了 keep-lived 保存了状态时才有效
activated() {
this.$router.push(this.path)
},
// 上一次离开之前
beforeRouteLeave(to,from,next){
this.path = this.$route.path;
next()
}
}
</script>

<style scoped>

</style>

效果

keep-lived 其他属性

include

字符串或正则表达,只有匹配的组件会被缓存

1
2
3
4
5
6
7
<keep-alive include="Profile">
<router-view></router-view>
</keep-alive>

<keep-alive include="Profile,Home">
<router-view></router-view>
</keep-alive>

exclude

字符串或正则表达,任何匹配的组件都不会被缓存

路径别名

Vue Cli 2.x 中可以在配置文件中配置路径别名

build文件夹下 webpack.base.conf.js

1
2
3
4
5
6
7
8
9
10
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'@': resolve('src'),
// 自定义路劲别名
'assets': resolve('src/assets'),
'components': resolve('src/components'),
'views': resolve('src/views')
}
}

注意

使用路径别名的时候,需要注意

不是 import 导入路径时,例如 src 需要加上 ~ 号

1
<img src="~assets/img/tabbar/profile.svg" alt="" slot="item-icon">

import 导入路径时不需要

1
import TabBarItem from "components/tabbar/TabBarItem";
文章作者:
文章链接: https://huohuohuohuohuohuo.github.io/2020/04/22/Vue-5-VueRouter/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自
打赏
  • 微信
    微信
  • 支付寶
    支付寶

评论