vue路由总结
1.简单路由
import Home from '../views/Home.vue' import admin from '../components/CourseList.vue' import detail from '../components/detail.vue' import login from '../views/login.vue' Vue.use(VueRouter) const routes = [ { path: '/', name: 'Home', component: Home }, { path: '/about', name: 'About', // route level code-splitting // this generates a separate chunk (about.[hash].js) for this route // which is lazy-loaded when the route is visited. // 懒加载 component: () => import(/* webpackChunkName: "about" */ '../views/About.vue') }, ] const router = new VueRouter({ routes })
懒加载:单独打包,按需加载。
懒加载的作用: vue这种单页面应用,如果我们不去做路由懒加载,打包之后的文件将会异常的大,就会造成进入首页时,需要加载的内容过多,时间过长,会出现长时间的白屏,不利于用户体验,运用懒加载就可以将页面进行划分,需要的时候加载页面,可以有效的分担首页所承担的加载压力,减少首页加载用时。
2.动态路由匹配
把某种模式匹配到所有的路由,全都映射到同个组件,使用动态路径参数(dynamic segment)
例如:添加详情页detail.vue
<div>
<h1>detail page</h1>
<h4>{{$route.params.name}}</h4>
</div>
其中,使用$route.params.name来接受路由传来的参数
课程列表中CourseList.vue,点击跳转:
<div
v-for="c in courses"
:key="c.name"
:
@click="onClick(c)"
>
<router-link :to='`/detail/${c.name}`'>
{{ c.name }} - {{ c.price | currency('¥') }}
</router-link>
</div>
router-link中的跳转,添加传参
路由中,router.js添加参数
{
path: '/detail/:name',
name: 'detail',
component: () => import ('../components/detail.vue')
}
这样,点击时可跳转到指定动态路由中,并传参
3.嵌套路由
指的是,在当前列表页面下,显示点击的详情页面,相当于,父路由点击后在父路由下显示子路由
路由中,router.js
{ path: '/admin', name:'admin', component: admin, children: [ { path: 'detail/:name', name: 'detail', component: detail } ], // 需要去认证 meta:{ auth: true },
形成了父子关系,注意,此时子路由中的path,千万不能写成'/detail/:name' 第一个/不需要,否则无法跳转,且不报错
course-list.vue: <router-link :to='`/admin/detail/${c.name}`'> {{ c.name }} - {{ c.price | currency('¥') }} </router-link> <!-- 嵌套路由的出口 --> <router-view></router-view>
需要注意的是,为了利于组件的重复使用,在使用嵌套或者动态路由匹配时,来回切换动态路由,该子路由中只会 创建一次,不会销毁,导致以下created中只触发切换的第一次,以后再切换时不会触发,
解决方法:使用watch监听路由变化
detail.vue:
// router来回切换时,只会调用第一次,以后切换不会再触发 // 原因是:组件的复用,不会销毁该组件 created(){ console.log('发送一次请求') }, // 处理办法watch监听 watch: { $route: { immediate: true, handler (){ console.log('详情获取') } } }
4.编程导航
之前的跳转是通过<router-link :to="路由"/>来进行跳转,也可以通过点击后代码实现跳转
router.push({name: '路由名称',params: {参数}, query: {查询字符串}})
例如:
列表页中 course-list.vue
<div class="course-list" v-else> <div v-for="c in courses" :key="c.name" : @click="onClick(c)" > {{ c.name }} - {{ c.price | currency('¥') }} </div> <router-view></router-view> </div> <script> onClick(c){ this.selectedCourse = c; // 编程导航方式 // this.$router.push(`/admin/detail/${c.name}`) // 命名路由方式 this.$router.push({ name: 'detail', params: {name: c.name} }) } </script>
5.路由守卫
路由守卫分为三个: 全局路由守卫,单个路由守卫、组件级路由守卫
路由守卫作用: 主要用来通过跳转或取消的方式守卫导航。
例如:权限设置。
新建login.vue,进入主页时给与判断,是否登录,如果没登录,跳转至登录页,登录后再进入主页
login.vue
<template> <div> <button @click="login" v-if="!isLogin">登录</button> <button @click="logout" v-else>注销</button> </div> </template> <script> export default { methods: { login(){ window.isLogin = true; // 跳转回跳转过来的那个页面 console.log(this.$route) this.$router.push(this.$route.query.redirect) }, logout(){ window.isLogin = false; this.$router.push(this.$route.query.redirect) } }, computed: { isLogin() { return window.isLogin } }, } </script> <style lang="scss" scoped> </style>
以上this.$route的打印内容:
5.1全局守卫
全局守卫包括:
router.beforeEach(是全局前置守卫)、
router.beforeResolve(是全局解析守卫)、
router.afterEach(是全局后置钩子)
每个导航守卫都接受3个参数 from 、to、next() ,参数的定义如下:
- to: Route: 即将要进入的目标 路由对象
- from: Route: 当前导航正要离开的路由
- next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。
router.js: 在路由中设置meta,守卫中获取其内的值,表示需要进行守卫
const routes = [ { path: '/admin', name:'admin', component: admin, children: [ { path: 'detail/:name', name: 'detail', component: detail } ], // 需要去认证 meta:{ auth: true }, }, { path: '/login', name: 'login', component: login, }, ] const router = new VueRouter({ routes }) // 全局守卫 router.beforeEach((to, from , next) =>{ // 判断是否需要守卫 // meta数据 if (to.meta.auth) { // 是否登录 if (window.isLogin) { next(); } else { next('/login?redirect='+ to.fullPath) } } else { next() } })
5.2单个路由守卫
含有一个守卫 : beforeEnter(to, from , next)守卫,使用情况如下:
const routes = [ { path: '/admin', name:'admin', component: admin, children: [ { path: 'detail/:name', name: 'detail', component: detail } ], // 局部守卫 beforeEnter(to, from ,next){ // 是否登录 console.log(to) if (window.isLogin) { next(); } else { next('/login?redirect='+ to.fullPath) } } }, { path: '/login', name: 'login', component: login, } ] const router = new VueRouter({ routes }) export default router
以上的to的打印内容
5.3 组件内守卫
直接在该组件中使用。
三个组件内守卫:
- beforeRouteEnter(to, from ,next) 前置,进入路由前调用
- beforeRouteUpdate(to, from , next) 更新,组件复用,路由跳转,比如:对于一个带有动态参数的路径,/foo/:id,在/foo/1和/foo/2之间跳转时,由于会渲染同样的Foo组件,因此这个组件实例会被复用,这个钩子函数就在这时使用。
- beforeRouteLeave(to, from, next) 后置,离开路由前调用
course-list.vue:
<script> export default { data() { return { selectedCourse: "", courses: [ { name: "javascript", price: 12324 }, { name: "python", price: 8989 } ], course: '' }; }, filters: { currency(value, symbol = "¥") { return symbol + value; } }, methods: { addCourse (){ this.courses.push({name: this.course, price: 1432}) }, onClick(c){ this.selectedCourse = c; // 编程导航 // this.$router.push(`/admin/detail/${c.name}`) this.$router.push({ name: 'detail', params: {name: c.name} }) } }, // 该组件内的路由守卫 beforeRouteEnter(to,from, next) { if (window.isLogin) { // 此时data还未创建,无法使用this next(vm => { console.log(vm.courses) }); } else { next('/login?redirect='+ to.fullPath) } } }; </script>
注意:beforeRouteEnter()内,无法调用this,因为我们使用的是进入路由之前,那会组件还没创建,得不到this这个属性,所有我们只能使用过vm异步语句来让节点上树
6.动态路由
通过router.addRoutes(routes)方式动态添加路由
例如:上例中,不将路由admin放入router.js中,如果登录了的话,动态的添加该路由,可以不通过路由守卫完成。
删除router.js中的admin路由,改至在登录页动态添加。
login.vue:
<template> <div> <button @click="login" v-if="!isLogin">登录</button> <button @click="logout" v-else>注销</button> </div> </template> <script> export default { methods: { login(){ window.isLogin = true; // console.log(this.$route,'123') // 动态添加路由 this.$router.addRoutes([ { path: '/admin', name:'admin', component: () => import('../components/CourseList.vue'), children: [ { path: 'detail/:name', name: 'detail', component: () => import('../components/detail.vue') } ] } ]) this.$router.push(this.$route.query.redirect) }, logout(){ window.isLogin = false; this.$router.push(this.$route.query.redirect) } }, computed: { isLogin() { return window.isLogin } }, } </script>
7.路由缓存
<keep-alive> <router-view></router-view> </keep-alive>
keep-alive:保持缓存,切换时不会改变其状态,不会加载。
同时,如果想保持某一个组件状态,可以在该组件中设置name,并在keep-alive中设置include,
exclude与include相反,表示除了该组件外的其他组件保持keep-alive.
例如:保持admin状态
admin中:
export default { name: 'admin', data() { return { selectedCourse: "", courses: [ { name: "javascript", price: 12324 }, { name: "python", price: 8989 } ], course: '' }; },
admin父组件中:
<keep-alive include="admin"> <router-view/> </keep-alive>
同时,keep-alive含有两个钩子函数
actived 和 deactived,使用keep-alive包裹的组件在切换时不会被销毁,而是缓存到内存中并执行 deactived 钩子函数,命中缓存渲染后会执行 actived 钩子函数。