Vue路由
路由就是一组KV的对应关系,多个路由需要经过路由器的管理,然后路由的主要目的就是用来写单页面应用
Uncaught TypeError: (0 , vue__WEBPACK_IMPORTED_MODULE_0__.defineComponent) is not a function
如果遇到这个报错,多半是Vue的版本和Vue-Router的版本不一致导致的,选择正确版本即可
我们就写一个单页面,需要一个文件夹专门用来存放路由
在src/router/index.js下
import VueRouter from 'vue-router'
//这里的两个组件是我自己写的组件
import About from '../components/about'
import Home from '../components/home'
export default new VueRouter({
routes: [
{
path: '/about',
component: About
},
{
path: '/home',
component: Home
}
]
})
然后我们在需要点击进行切换的a标签换成<router-link></router-link>
标签,如果标签里面有需要那种选中后的样式那么我们可以使用active-class
然后加上类即可,最后在需要展示路由页面内容的地方写上<router-view></router-view>
即可显示内容
<router-link class="list-group-item" active-class="active" to="/about">About</router-link>
<router-link class="list-group-item" active-class="active" to="/home">Home</router-link>
然后组件之间的切换,首先会销毁当前组件,然后挂在新的组件
只要是使用了router的组件身上都会多两个东西$route
和$router
,route每个组件都有一个,router只有一个,也就是共用一个
嵌套路由
套娃
import VueRouter from 'vue-router'
import About from '../pages/about'
import Home from '../pages/home'
import News from '../pages/News'
import Message from '../pages/Message'
export default new VueRouter({
routes: [
{
path: '/about',
component: About
},
{
path: '/home',
component: Home,
//对于组件的子组件,需要children这个配置项
children: [
{
//这里不需要反斜杠 写了就G
path: 'news',
component: News
},
{
path: 'message',
component: Message
}
]
}
]
})
然后在跳转的标签上
<router-link class="list-group-item" active-class="active" to="/home/news">News</router-link>
<!-- 这里的to一定要带上父组件的路径 -->
路由的query参数
在$route
属性里面有一个query,这个东西就是我们传参的关键
<router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`">{{m.title}}</router-link>
上面的代码解决了很多问题,比如传递参数的时候如果要使用插值语法该怎么办,当我们是有上面的语法后就可以使用$route.query.id
这样去在其他路由里面拿参数
当然这样写可读性比较差,而且比较乱,Vue也提供了另外一种方式
<router-link :to="{
path: '/home/message/detail',
query: {
id: m.id,
title: m.title
}
}">{{m.title}}</router-link>
命名路由
上面我们会发现这个path有点长,我们就可以使用命名路由来解决这个问题
routes: [
{
path: '/about',
component: About
},
{
path: '/home',
component: Home,
children: [
{
path: 'news',
component: News
},
{
path: 'message',
component: Message,
children: [
{
name: 'check', //这里加了个name属性
path: 'detail',
component: Detail
}
]
}
]
}
]
<router-link :to="{
name: 'check',
query: {
id: m.id,
title: m.title
}
}">{{m.title}}</router-link>
于是乎,我们就可以写成这样
路由的params参数
routes: [
{
path: '/about',
component: About
},
{
path: '/home',
component: Home,
children: [
{
path: 'news',
component: News
},
{
path: 'message',
component: Message,
children: [
{
name: 'check',
path: 'detail/:id/:title', //这里添加了两个站位
component: Detail
}
]
}
]
}
]
<router-link :to="{
//这里必须使用name配置
name: 'check',
//这里把query改成params
params: {
id: m.id,
title: m.title
}
}">{{m.title}}</router-link>
然后就可以使用$route.params.id
这样去在其他路由里面拿参数
注意:路由携带params参数时,若使用to的对象写法,则不能使用path配置项,必须使用name配置!
路由的prop配置
作用:让路由组件更方便的收到参数
{
name:'xiangqing',
path:'detail/:id',
component:Detail,
//第一种写法:props值为对象,该对象中所有的key-value的组合最终都会通过props传给Detail组件
// props:{a:900}
//第二种写法:props值为布尔值,布尔值为true,则把路由收到的所有params参数通过props传给Detail组件
// props:true
//第三种写法:props值为函数,该函数返回的对象中每一组key-value都会通过props传给Detail组件
props(route){
return {
id:route.query.id,
title:route.query.title
}
}
}
Router-link的replace属性
作用:控制路由跳转时操作浏览器历史记录的模式
说白了就是点完了之后能不能前进或者后退,然后有两个模式,一个是push,一个是replace,push
是追加历史记录,replace
是替换当前记录。路由跳转时候默认为push
Router-link标签加一个replace属性就开启了
编程式路由导航
作用:不借助<router-link>
实现路由跳转,让路由跳转更加灵活
具体编码(在methods里面:
//$router的两个API
this.$router.push({
name:'xiangqing',
params:{
id:xxx,
title:xxx
}
})
this.$router.replace({
name:'xiangqing',
params:{
id:xxx,
title:xxx
}
})
this.$router.forward() //前进
this.$router.back() //后退
this.$router.go() //可前进也可后退 参数为前进几层
缓存路由组件
作用:让不展示的路由组件保持挂载,不被销毁。
具体编码,不带include的话这个标签下所有的路由都不会被销毁,带上就只会保留对应的组件:
<keep-alive include="News">
<router-view></router-view>
</keep-alive>
<!-- 多个写法 -->
<keep-alive :include="['News', 'Message']">
<router-view></router-view>
</keep-alive>
和路由组件相关的生命周期钩子
- 作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。
- 具体名字:
activated
路由组件被激活时触发。deactivated
路由组件失活时触发。
路由守卫
-
作用:对路由进行权限控制
-
分类:全局守卫、独享守卫、组件内守卫
-
全局守卫:
//全局前置守卫:初始化时执行、每次路由切换前执行 router.beforeEach((to,from,next)=>{ console.log('beforeEach',to,from) if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制 if(localStorage.getItem('school') === 'scitc'){ //权限控制的具体规则 next() //放行 }else{ alert('暂无权限查看') // next({name:'scitc'}) } }else{ next() //放行 } }) //全局后置守卫:初始化时执行、每次路由切换后执行 router.afterEach((to,from)=>{ console.log('afterEach',to,from) if(to.meta.title){ document.title = to.meta.title //修改网页的title }else{ document.title = 'vue_test' } })
-
独享守卫:
注意啊,这个守卫没有后置的,只有前置的
beforeEnter(to,from,next){ console.log('beforeEnter',to,from) if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制 if(localStorage.getItem('school') === 'scitc'){ next() }else{ alert('暂无权限查看') // next({name:'scitc'}) } }else{ next() } }
-
组件内守卫:
这个是写在组件里面的
//进入守卫:通过路由规则,进入该组件时被调用 beforeRouteEnter (to, from, next) { }, //离开守卫:通过路由规则,离开该组件时被调用 beforeRouteLeave (to, from, next) { }