Vue路由守卫详解

it2024-10-30  35

路由导航过程中有若干生命周期钩子,可以在这里实现逻辑控制。

全局守卫,router.js

//路由配置 { path: '/about', name: "about", meta: {auth: true}, //需要认证 component: ()=>import(/*webpackChunkName: "about"*/ "./views/About.vue") } //全局守卫 router.beforeEach((to,from,next)=>{ //要访问/about 且未登录需要去登录 if(to.meta.auth && !window.isLogin){ if(window.confirm('请登录')){ //用户操作了登录 window.isLogin = true; next(); //登录成功,继续 }else{ next('/'); //放弃登录,回首页 } }else{ next(); //不需登录,继续 } })

token放在本地安全吗?有什么隐患?

路由独享守卫

beforeEnter(to,from,next){ //路由内部知道自己需要认证 if(!window.isLogin){ //... }else{ next(); } }

组件内的守卫

export default{ beforeRouteEnter(to,from,next){ // 在渲染该组件的对应路由被 confirm 前调用 // 不!能!获取组件实例 `this` // 因为当守卫执行前,组件实例还没被创建 }, beforeRouteUpdate(to,from,next){ // 在当前路由改变,但是该组件被复用时调用 // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候, // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。 // 可以访问组件实例 `this` }, beforeRouteLeave(to,from,next){ // 导航离开该组件的对应路由时调用 // 可以访问组件实例 `this` } }

组件内的守卫项目应用场景:

项目中某一课程列表中的推荐课程,每次调接口都会重新返回一批不同的课程,进入课程列表看到的课程,在点击进入下级页面再回来,希望能看到刚刚进来时的数据,所以只要是页面返回当前页,需判断不重新调推荐课程接口。

export default{ name:'learnProgram', data(){ return { } }, mounted(){ }, methods:{ getRecommendCourse(){ let params = { userName:this.userName || '' } this.$ajax({ type:'get', url:'/course/getCourseByRandom', data:params }).then((res)=>{ if(res.data.items.length != 0){ this.recomendList = res.data.,items this.$store.commit('keeplearnPrgClass.recommendCourse',this.recomendList) } }) }, setData(){ //存到vuex中,返回时从vuex中取 this.$store.commit('keeplearnPrgClass.recommendCourse',[]) this.getRecommendCourse() }, setLocalData(){ //返回时从vuex中取 this.recomendList = this.$store.state.keeplearnPrgClass.recommendCourse } }, beforeRouteEnter(to,from,next){ if(from.name == 'myMap' || from.name == null){ next(vm=>vm.setData()) }else{ next(vm=>vm.setLocalData) } }, }

Vue-router拓展

动态路由

利用$router.addRoutes()可以实现动态路由添加,常用于用户权限控制。

//router.js //返回数据可能是这样的 //[{ // path: "/", // name: 'home', // component: 'Home' //}] //异步获取路由 api.getRoutes().then(routes => { const routeConfig = routes.map(route => mapComponent(route)); router.addRoutes(routeConfig); }) //映射关系 const compMap = { 'Home': () => import('./views/Home.vue') } //递归替换 function mapComponent(route){ route.component = compMap[route.component]; if(route.children){ route.children = route.children.map(child => mapComponent(child)) } return route }

面包屑

利用$route.matched可得到路由匹配数组 ,按顺序解析可得路由层次关系。

//Breadcrumb.vue watch: { $route(){ //[{name:'home'},{name:'list'}] console.log(this.$route.matched); //['home','list'] this.crumbData = this.$toute.matched.map(m => m.name) } }

Vue-router 源码实现

通常用法

//krouter.js import Home from './views/Home'; import About from './views/About'; Vue.use(VueRouter); export default new VueRouter({ routes: [ {path: '/',component: Home}, {path: '/about', component: Abbout} ] }) //main.js import router from './krouter'

分析一下需要完成的任务:

要能解析routes配置,变成一个key为path,value为component的map要能监控url变化事件,把最新的hash值不保存到current路由要定义两个全局组件:router-view用于显示匹配组件内容,router-link用于修改hashcurrent应该是响应式的,这样可以触发router-view的重新渲染

具体实现

创建krouter.js

let Vue; class VueRouter{ constructor(options){ this.$options = options; //创建一个路由path和route映射 this.routeMap = {}; //将来当前路径current需要响应式 //利用Vue响应式原理可以做到这一点 this.map = new Vue({ data: { current: '/' } }) } init(){ //绑定浏览器事件 this.bindEvents(); //解析路由配置 this.createRouteMap(this.$options) //创建router-link和 this.initComponent() } bindEvents(){ window.addEventListener('hashchange',this.onHashchange.bind(this)) window.addEventListener('load',this.onHashchange.bind(this)) } onHashchange(e){ // http://localhost/#/home this.app.current = window.location.hash.slice(1) || '/' } createRouteMap(options){ options.routes.forEach(item => { // ['/home']: {path: '/home',component: Home} this.routeMap[item.path] = item; }) } initComponent(){ Vue.component('router-link',{ props: { to: String }, render(h){ //目标是:<a :href="to"> return h('a', {attrs:{href:'#'+this.to}}, this.$slots.default) //jsx 写法 // return <a href={this.to}>{this.$slots.default}</a> } }) //hash -> current -> render Vue.component('router-view',{ //箭头函数能保留this指向,这里指向VueRouter实例 render: (h) => { const Comp = this.routeMap[this.app.current].component; return h(Comp); } }) } } //把VueRouter 变为插件 VueRouter.install = function(_Vue){ Vue = _Vue; //这里保存,上面使用 //混入任务 Vue.mixin({ //混入:就是扩展Vue beforeCreate(){ //这里的代码将来会在外面初始化的时候被调用 //这样我们就实现了Vue扩展 // this 是谁? Vue的组件实例 //但是这里只希望跟组件执行一次,只有跟组件有 $options.router if(this.$options.router){ Vue.prototype.$touter = this.$options.router; this.$options.router.init(); } } }) }
最新回复(0)