前言
本篇博客主要回顾了vue-router的相关知识点。
面试回答
1.Link标签:Link标签本质上也是a标签,不过它禁止了a标签的默认事件,通过history的相关事件来进行跳转,route内部也可以通过捕获这个事件来进行相关的逻辑处理。
2.路由导航:路由的钩子函数有三类,全局守卫、路由守卫、组件内守卫。全局守卫在每次导航时都会触发,一般会新起一个文件,然后引入main.js中,涉及的钩子函数有beforeEach、afterEach、beforeReslove等。路由守卫则是在进入路由时触发,一般在定义路由的时候使用,比如在路由路径下添加一个的属性beforeEnter。组件内守卫则是在进入或离开组件前调用。这三种守卫一般都包含三个参数to、from、next,to和from不多说了,next参数可以不添加,但是一旦添加,则必须调用一次,否则路由跳转就会停止。
3.组件递归:首先要为组件命名name,这样可以在组件内继续调用该组件,然后可以用v-for去循环,这边key最好使用唯一ID,免得增加不必要的消耗,且需要判断传入数据是否为空,告知v-for什么时候停止渲染,数据的话仍旧使用树形结构的数据即可。组件名称name同时也可以搭配keep-alive使用,它能使被包含的组件保留状态,避免重新渲染,这里相关的属性有include、exclude以及activated和deactivated两个钩子函数。
4.mode模式:路由提供hash以及history两种方式,默认是hash,它们在url上的区别是hash模式会有一个#的锚点来区分,而history没有。在原理上的区别是hash模式利用了window可以监听onhashchange事件来实现的,而history模式是通过调用window.history对象上的一系列方法来实现,比如pushState和replaceState方法。在与服务器交互上的区别是hash模式只会将#锚点前的url发送给服务器,而history模式则会将完整的url发送给服务器,因此在生产环境中,history模式需要服务器设置代理转发,对于不识别的路径,统一处理重定向到项目首页,否则在刷新的时候会出现404的情况。
知识点
1.路由
路由跳转
router-link:实际为a标签,不过它禁止了a标签的默认事件,通过history的相关事件来进行跳转。
<router-link :to="keyframes"> <div>zxp</div> </router-link> //keyframes为router中的path
replace
this.$router.replace({path:'/user'}) //该方式,history栈中不会有记录
go
this.$router.go(n) //向前或者向后跳转n个页面,n可为正整数(向后)或负整数(向前)
- 带参跳转
动态路由
getRouter(id){ this.$router.push({ path:`test/${id}` }) } //path后的引号得用模板字符串,而不是单引号,因为有变量 { path:'/user/:userId', component:User } //获取的路由如:'/user/123456' //this.$route.userId 123456
param传递
this.$router.push({ name:'test', params:{ id:id } }) //获取方式:this.$route.params.id //该方式类似get请求,浏览器url在路径后面会显示id值,去掉id页面加载会异常
query传递
this.$router.push({ name:'test', query:{ id:id } }) //获取方式:this.$route.query.id //该方式类似post请求,浏览器url不显示id值
路由懒加载
路由懒加载也叫作延迟加载,使用懒加载可以减少我们第一次打开项目首页的时间,不至于页面出现长时间的白屏,从而优化用户的体验。
export default new Router({
routes: [
{
path: '/test',
name: 'testRouter',
component: () => import('../page/test.vue')
}
]
})
嵌套路由、重定向
{
path: '/parent',
component: () => import('../page/parent.vue'), // 父路由的公共部分
redirect:'/parent/common'
children: [
{
path: 'common', // 进入父路由时,重定向跳转
name: 'common',
component: () => import('../page/common.vue')
},
{
path: 'child',// 其他子路由,这里注意,不要加 '/',否则会匹配根路由
name: 'child',
component: () => import('../page/child.vue')
}
]
}
2.导航守卫
导航守卫主要用来通过跳转或取消的方式守卫导航。有多种机会植入路由导航过程中:全局的, 单个路由独享的, 或者组件级的。 参考链接:https://juejin.cn/post/7139932176141893669
- 全局导航守卫
全局路由守卫有三种:
全局前置守卫:router.beforeEach,主要作用就是用于在进入路由前做一些逻辑操作,如登录验证;
// 缓存登录状 sessionStorage.setItem('username',this.ruleForm.username) // main.js router.beforeEach((to,from,next) => { //路由跳转的前置钩子 if(!sessionStorage.getItem('username') && to.name !== 'login') { next({name: 'login'}) // 路由名称 }else{ next() } })
全局解析守卫:router.beforeResolve
官方解释其与beforeEach的区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用,即在beforeEach和组件内beforeRouteEnter之后,afterEach之前调用。
// main.js router.beforeResolve((to,from,next) => { console.log(to,from); next() })
PS:以上两个钩子函数执行时,还在当前页面,未跳转到跳转的页面
全局后置守卫:router.afterEach
和beforeEach相反,它是在路由跳转完成后触发,参数包括to,from没有了next,它发生在beforeEach和beforeResolve之后,beforeRouteEnter(组件路由守卫)之前,它是在路由跳转之后触发的,可以获取到路由跳转之后的dom结构。
router.afterEach((to,from) => { console.log(to,from); if(!sessionStorage.getItem('username') && to.name !== 'login') { router.push('/login') } })
独享守卫
beforeEnter(独享守卫)通常是某一个或几个页面独有的,所以我们通常会将路由独享守卫写在/src/router/index.js里,目的是有些需要要求进入一些页面有要求,比如要求已登录的状态等,如购物车。
// router/index.js { path: '/detail', name: 'detail', component: () => import('@/views/Detail.vue'), beforeEnter: (to,from,next) => { if(!sessionStorage.getItem('username')) { alert('请先登录') // next({name: 'login'}) router.push('/login') } else { next() } } }
组件路由守卫
组件路由守卫是组件内的钩子函数,类似于组件内的生命周期,钩子函数执行的顺序包括beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave三个,执行位置如下:
<template> ... </template> export default{ data(){ //... }, beforeRouteEnter (to, from, next) { // 在渲染该组件的对应路由被 confirm 前调用 // 不!能!获取组件实例 `this` // 因为当守卫执行前,组件实例还没被创建 }, beforeRouteUpdate (to, from, next) { // 在当前路由改变,但是该组件被复用时调用 // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候, // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。 // 可以访问组件实例 `this` }, beforeRouteLeave (to, from, next) { // 导航离开该组件的对应路由时调用 // 可以访问组件实例 `this` } } <style> ... </style>
- 但凡涉及到有next参数的钩子,必须调用next()才能继续往下执行下一个钩子,否则路由跳转等会停止。
- 如果要中断当前的导航要调用next(false)。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到
from
路由对应的地址。(主要用于登录验证不通过的处理) - next('/')或者next({ path: '/' }): 跳转到一个不同的地址,可传递的参数与router.push中选项一致。
- 在beforeRouteEnter钩子中next((item)=>{})内接收的回调函数参数为当前组件的实例item,这个回调函数在生命周期mounted之后调用,也就是,他是所有导航守卫和生命周期函数最后执行的那个钩子。
3.keep-alive
keep-alive
可以实现组件缓存,当组件切换时不会对当前组件进行卸载。 它的原理是在created函数调用时将需要缓存的vnode节点保存在this.cache当中,如果符合条件则从cache取出vnode实例进行渲染。
主要是有以下三个属性
- include:需要缓存的数据,支持字符串,数组,正则
- exclude:不需要缓存的数据,支持字符串,数组,正则
max:缓存的最大组件数量,支持数字和字符串,如果超过了这个个数的话,在下一个新实例创建之前,就会将以缓存组件中最久没有被访问到的实例销毁掉。
基础使用方式:
//router.js import Vue from 'vue' import Router from 'vue-router' import Home from './views/Home.vue' Vue.use(Router) export default new Router({ routes: [ { path: '/', name: 'home', component: Home, // 需要被缓存 meta: { keepAlive: true //这里的keepAlive可以自定义,比如noCache,那么在使用时也需要同步,如下Layout.vue } }, { path: '/about', name: 'about', component: () => import('./views/About.vue') }, ] }) //布局组件,如Layout.vue <template> <div id="app"> //keep-alive包裹的子组件只能有一个 <keep-alive> <router-view v-if="$route.meta.keepAlive"></router-view> </keep-alive> <router-view v-if="!$route.meta.keepAlive"></router-view> </div> </template>
组件一旦被keep-alive缓存,那么就不会再执行created、mounted等钩子函数, 因此提供了activated和deactivated钩子函数,执行顺序:第一次进入-->created--> mounted--> activated -->退出-->deactivated -->第二次进入-->activated
注意事项:
- keep-alive先匹配被包含组件的name字段,如果name不可用,则匹配当前组件component配置中的注册名称
- keep-alive不会在函数式组件中正常工作,因为它们没有缓存实例。
- 当匹配条件同时在include与exclude存在时,以exclude优先级最高。
- 包含在keep-alive中,但符合exclude,不会调用activated和deactivated
4.路由模式
前端路由有两种模式:hash模式和history模式,下面具体来看看其特点:
history
history允许开发者直接更改前端路由,即更新浏览器URL地址而不重新发起请求,并且提供了丰富的函数供开发者调用,比如
history.replaceState({}, null, '/b') // 替换路由 history.pushState({}, null, '/a') // 路由压栈 history.back() // 返回 history.forward() // 前进 history.go(-1) // 后退1次
hash
hash模式是一种把前端路由的路径用
#
拼接在真实URL后面的模式。当井号#
后面的路径发生变化时,浏览器并不会重新发起请求,而是会触发hashchange
事件,这种方式浏览器兼容性较好,连 IE8 都支持,但由于有个#比较丑,一般就不采用。区别
- 在url上,hash模式会有一个#的锚点来区分,而history没有。
- 在原理上,hash模式利用了window可以监听onhashchange事件来实现的,而history模式是通过调用window.history对象上的一系列方法来实现,比如pushState和replaceState方法。
- 在与服务器交互上,hash模式只会将#锚点前的url发送给服务器,而history模式则会将完整的url发送给服务器,因此在生产环境中,history模式需要服务器设置代理转发,对于不识别的路径,统一处理重定向到项目首页,否则在刷新的时候会出现404的情况。
最后
走过路过,不要错过,点赞、收藏、评论三连~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。