路由的本质就是一些key
、value
组成的映射关系,每一个key
都会指向一个value,多个路由(route)需要通过一个路由器(router)进行管理。
vue中的路由,目的就是实现单页面应用(SPA - single page web application),是vue的一个插件库。
1、安装vue-router
注意:vue-router@4
只能在vue3中使用,vue-router@3
可以在vue2中使用
cnpm i vue-router@3
2、src下新建router/index.js
,Vue使用VueRouter,并且配置router实例
// 该文件用于创建整个应用的route
import VueRouter from "vue-router"
import Vue from 'vue'
//使用VueRouter
Vue.use(VueRouter);
//创建并暴露一个VueRouter实例
export default new VueRouter({
routes: []
})
3、main.js
中引入router,并配置到Vue实例
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
//引入router
import router from './router'
new Vue({
render: h => h(App),
//配置router到Vue实例
router
}).$mount("#app")
router/index.js
中引入要切换的组件,并配置路径
import VueRouter from "vue-router"
import Vue from 'vue'
Vue.use(VueRouter);
import Home from '../view/Home.vue'
import About from '../view/About.vue'
export default new VueRouter({
routes: [
//重定向根路径/到/home
{
path: "/",
redirect: "/home";
},
{
path: "/home",
component: Home
},
{
path: "/about",
component: About
}
]
})
两个组件Home.vue
和About.vue
<template>
<div>
is About
</div>
</template>
<script>
export default {
name: "About",
}
</script>
<template>
<div>
is Home
</div>
</template>
<script>
export default {
name: "Home",
}
</script>
App.vue
中创建了两个路由链接和路由展示标签
<template>
<div>
<!-- roter-link相当于a标签,只不过href需要换成to,值就是roter中配置的path -->
<router-link to="/home" active-class="ac">Home</router-link>/
<!-- replace:本次的浏览记录会替换掉上次的 -->
<router-link replace to="/about" active-class="ac">About</router-link><br>
<!-- 用于展示路由的标签 -->
<router-view/>
</div>
</template>
<script>
export default {
name: "App"
}
</script>
<style scoped>
/* 选中样式 */
.ac{
color: red;
}
</style>
1、开发中,一般组件和路由组件通常放在src下不同的文件夹中,易于区分。一般情况下,一般组件放在components
文件夹下,路由组件放在views
文件夹下
2、组件在切换的时候才会进行创建挂载、切换到其他组件后,当前组件将被销毁
3、在使用了vue-route插件后,所有的组件实例对象上,都会多两个属性$route
(保存当前路由信息)、$router
(全局路由实例)
router/index.js
import VueRouter from "vue-router"
import Vue from 'vue'
Vue.use(VueRouter);
import Home from '../pages/Home.vue'
import About from '../pages/About.vue'
import Ab1 from '../pages/Ab1.vue'
import Ab2 from '../pages/Ab2.vue'
export default new VueRouter({
routes: [
{
path: "/home",
component: Home
},
{
path: "/about",
component: About,
//使用children属性声明子路由
children:[
{ // 注意:对于子路由,路由不需要加/
path: "ab1",
component: Ab1
},
{
path: "ab2",
component: Ab2
}
]
}
]
})
About.vue
进行子路由的跳转和展示
<template>
<div>
is About<br>
<router-link to="/about/ab1">ab1</router-link>/
<router-link to="/about/ab2">ab2</router-link>
<router-view/>
</div>
</template>
<script>
export default {
name: "About",
}
</script>
App.vue
<template>
<div>
<router-link to="/home" active-class="ac">Home</router-link>/
<router-link to="/about" active-class="ac">About</router-link><br>
<router-view/>
</div>
</template>
<script>
export default {
name: "App",
}
</script>
<style scoped>
/* 选中样式 */
.ac{
color: red;
}
</style>
命名路由用来简化路由跳转时的完整路径(只是简化编码,并不简化地址栏显示)
import VueRouter from "vue-router"
import Vue from 'vue'
Vue.use(VueRouter);
import Home from '../pages/Home.vue'
import About from '../pages/About.vue'
import Info from '../pages/Info.vue'
export default new VueRouter({
routes: [
{
path: "/home",
component: Home
},
{
path: "/about",
component: About,
children:[
{
//配置命名路由
name: "abInfo",
path: "info",
component: Info
}
]
}
]
})
使用命名路由
<!-- 跳转的时候,就可以直接写路由的name值 -->
<router-link to="abInfo">info</router-link><br>
可以对路由组件进行传参
这种方法适合传少量的参数
About.vue
,通过路径给子路由传参
<template>
<div>
学生信息<br>
<!-- 利用路由跳转路径传参 -->
<router-link :to="'/about/info?id=' + s.id + '&name=' + s.name + '&age=' + s.age" v-for="s in stu" :key="s.id">
{{s.name}}
<br/>
</router-link>
<router-view/>
</div>
</template>
<script>
export default {
name: "About",
data() {
return {
stu: [
{id: "001",name: "lucy",age: "18"},
{id: "002",name: "tom",age: "22"},
{id: "003",name: "lily",age: "16"},
{id: "004",name: "james",age: "23"},
{id: "005",name: "marry",age: "17"},
],
};
},
}
</script>
Info.vue
,通过this.$route.query
接收路径中的参数
<template>
<div>
<!-- 通过this.$route.query可以获取路径中拼接的参数 -->
编号:{{$route.query.id}}<br/>
姓名:{{$route.query.name}}<br/>
年龄:{{$route.query.age}}<br/>
</div>
</template>
<script>
export default {
name: "Ab1",
}
</script>
这种方法可以传任何的对象
About.vue
<template>
<div>
学生信息<br>
<!-- 使用对象进行传递参数 -->
<router-link :to="{path:'/about/info',query:{stu:s}}" v-for="s in stu" :key="s.id">
{{s.name}}
<br/>
</router-link>
<router-view/>
</div>
</template>
<script>
export default {
name: "About",
data() {
return {
stu: [
{id: "001",name: "lucy",age: "18"},
{id: "002",name: "tom",age: "22"},
{id: "003",name: "lily",age: "16"},
{id: "004",name: "james",age: "23"},
{id: "005",name: "marry",age: "17"},
],
};
},
}
</script>
Info.vue
<template>
<div>
<!-- 通过this.$route.query可以获取query中的参数 -->
编号:{{$route.query.stu.id}}<br/>
姓名:{{$route.query.stu.name}}<br/>
年龄:{{$route.query.stu.age}}<br/>
</div>
</template>
<script>
export default {
name: "Ab1",
}
</script>
可以在路径直接传参,不需要k1=val&k2=val
注意:这种方法,需要在路由配置中声明占位参数
index.js
,声明路由路径的占位参数
export default new VueRouter({
routes: [
{
path: "/home",
component: Home
},
{
path: "/about",
component: About,
children:[
{
// 声明占位参数
path: "info/:id/:name/:age",
component: Info
}
]
}
]
})
About.vue
<template>
<div>
学生信息<br>
<!-- 使用拼接字符串进行传递参数 -->
<router-link :to="'/about/info/' + s.id + '/' + s.name + '/' + s.age" v-for="s in stu" :key="s.id">
{{s.name}}
<br/>
</router-link>
<router-view/>
</div>
</template>
<script>
export default {
name: "About",
data() {
return {
stu: [
{id: "001",name: "lucy",age: "18"},
{id: "002",name: "tom",age: "22"},
{id: "003",name: "lily",age: "16"},
{id: "004",name: "james",age: "23"},
{id: "005",name: "marry",age: "17"},
],
};
},
}
</script>
Info.vue
<template>
<div>
<!-- 通过this.$route.params可以获取路径中拼接的参数 -->
编号:{{$route.params.id}}<br/>
姓名:{{$route.params.name}}<br/>
年龄:{{$route.params.age}}<br/>
</div>
</template>
<script>
export default {
name: "Ab1",
}
</script>
注意:此处必须使用命名路由,不可以使用path
index.js
,声明命名路由和占位参数
export default new VueRouter({
routes: [
{
path: "/home",
component: Home
},
{
path: "/about",
component: About,
children:[
{
name: "abInfo",
path: "info/:id/:name/:age",
component: Info
}
]
}
]
})
About.vue
<template>
<div>
学生信息<br>
<!-- 使用对象进行传递参数 -->
<router-link :to="{name:'abInfo',params: {id:s.id,name:s.name,age:s.age}}" v-for="s in stu" :key="s.id">
{{s.name}}
<br/>
</router-link>
<router-view/>
</div>
</template>
<script>
export default {
name: "About",
data() {
return {
stu: [
{id: "001",name: "lucy",age: "18"},
{id: "002",name: "tom",age: "22"},
{id: "003",name: "lily",age: "16"},
{id: "004",name: "james",age: "23"},
{id: "005",name: "marry",age: "17"},
],
};
},
}
</script>
Info.vue
<template>
<div>
<!-- 通过this.$route.params可以获取路径中拼接的参数 -->
编号:{{$route.params.id}}<br/>
姓名:{{$route.params.name}}<br/>
年龄:{{$route.params.age}}<br/>
</div>
</template>
<script>
export default {
name: "Ab1",
}
</script>
可以让路由更加简便的接收参数
export default new VueRouter({
routes: [
{
path: "/home",
component: Home
},
{
path: "/about",
component: About,
children:[
{
name: "abInfo",
path: "info/:id/:name/:age",
component: Info,
//1、对象写法,该对象中的所有属性,可以作为组件Info的data使用
//props: {a:1,b:2}
//2、布尔写法,如果为ture,就会将路由参数params所有值,以props形式传给Info组件
//props: ture
//3、函数写法,参数是$route,返回值对象中的所有属性,可以作为组件Info的data使用
props(route){
return {id:"001",name:"lucy"}
}
}
]
}
]
})
除了使用router-link
标签实现路由跳转,还可以使用js代码完成跳转。由于所有的组件实例对象都有一个$router
属性,就可以通过这个属性来操作跳转。
//push、replace传参和在router-link中to属性值一样
//1、直接传入路径
this.$router.push("/home");
this.$router.replace("/about");
//2、传入对象
this.$router.push({
path:'/about/info',
query:{stu:s}
});
this.$router.replace({
name:'abInfo',
params: {
id:s.id,
name:s.name,
age:s.age
}
});
//back可以后退一步
this.$router.back()
//forward可以前进一步
this.$router.forward()
//go可以跳转历史,前进指定的步数
//后退两步
this.$router.go(-2)
在router的index.js中添加,避免路由重复push导致控制台爆红Avoided redundant navigation to current location
const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(location) {
return originalPush.call(this, location).catch(err => err)
}
由于组件在切换的时候,老的组件会被销毁,组件中的数据会丢失;但是在实际开发中,例如表单数据,希望在切换组件后,再回来还能保持,那么就需要使用缓存路由组件
<!-- 使用该标签,默认情况下,router-view中展示的所有组件都会被销毁 -->
<!-- 也可以使用include属性,指定需要缓存的组件name -->
<!-- 对于多个组件,可以使用逗号分隔,也可以使用v-bind -->
<keep-alive include="Home">
<router-view/>
</keep-alive>
路由组件除了有普通组件的生命周期钩子外,还有自己独有的钩子
路由组件被激活(显示)
路由组件失活(切换到其他组件)
注意:在实际开发中,路由守卫进行校验,如果都是用name、path进行校验,那么不容易维护,而且逻辑混乱,这个时候,我们可以例如route的meta属性(路由元信息),添加一个boolean类型的参数,来判断该路由是否需要校验。
在router/index.js
中对router对象进行配置,在路由的切换前进行回调(路径不发生变化),一般用于对路由切换的合法性进行验证
router.beforeEach(function(to,from,next){})
,beforeEach接收一个回调函数,这个函数有三个参数
to
:想要切换到的目标route对象
from
:来源的route对象
next
:是一个函数,如果调用的话,说明放行(进行切换)
在router/index.js
中对router对象进行配置,在路由的切换后进行回调(路径已经变化),一般用于组件切换后的渲染,例如title的变化
router.afterEach(function(to,from){})
,afterEach接收一个回调函数,这个函数有两个参数
to
:想要切换到的目标route对象
from
:来源的route对象
在route配置项中进行配置,只对当前的route生效
独享路由守卫只有前置beforeEnter(function(to,from,next){})
,参数使用和全局前置一样,没有后置
直接声明在路由组件的配置项中,注意:beforeRouteEnter中,不能获取组件实例对象this
beforeRouteEnter(to,from,next){}
,通过路由规则进入当前组件时进行调用
beforeRouteLeave(to,from,next){}
,通过路由规则离开当前组件时进行调用
http://localhost:8080/#/search
#
后面的路径都为hash路径,这一部分路径不会传给服务器http://localhost:8080/search
mode
选项进行切换注意:如果使用history模式,可能会导致路由刷新404,这是因为浏览器向服务器发送了请求,而服务器没有这个资源,解决方式,例如nginx,添加如下配置
# 解决vue路由模式为history时刷新返回404的问题
location / {
root /usr/share/nginx/html;
index /index.html;
// 找不到文件则尝试直接返回index.html,而vue路由会监控地址栏的俩变化,因此还是在当前页刷新的效果
try_files $uri $uri/ /index.html;
}
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'home',
component: () => import('../views/Home.vue') //进行l
},
{
path: '/about',
name: 'about',
component: () => import('../views/About.vue')
}
]
const router = new VueRouter({
routes
})
export default router