分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > 技术分享

VueJs(12)---vue-router(导航守卫,路由元信息)

发布时间:2023-09-06 01:53责任编辑:白小东关键词:暂无标签

vue-router(导航守卫,路由元信息)

        之前泄露两篇有关vue-router博客:

       VueJs(10)---vue-router(进阶1)

       VueJs(11)---vue-router(进阶2)

一、导航守卫

        当做Vue-cli项目的时候感觉在路由跳转前做一些验证,比如登录验证,是网站中的普遍需求,这个时候就需要导航守卫,你可以在页面跳转前做逻辑判断,时候跳转,跳转到指定页面。

       (1)全局的(beforeEach,afterEach,beforeResolve),

       (2)单个路由独享的(beforeEnter),

       (3)组件级的(beforeRouteEnter,beforeRouteUpdate,beforeRouteLeave)。

1、全局守卫

   你可以使用 router.beforeEach 注册一个全局前置守卫:

const router = new VueRouter({ ... })router.beforeEach((to, from, next) => { ?// 业务逻辑处})

   每个守卫方法接收三个参数:

  • to: Route: 即将要进入的目标 路由对象

  • from: Route: 当前导航正要离开的路由

  • next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。

   next(): 进行管道中的下一个钩子。这个是必须要的,否在无法完成跳转。

   next(false): 中断当前的导航。就相当于点击之后不会跳转到指定页面,就相当于没有写next()一样。

   next(‘/‘) 或者 next({ path: ‘/‘ }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向 next 传递任意位置对象,

   next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。

     确保要调用 next 方法,否则钩子就不会被 resolved。

全局后置钩子

    你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身

router.afterEach((to, from) => { ?// ...})

路由独享的守卫

   你可以在路由配置上直接定义 beforeEnter 守卫

const router = new VueRouter({ ?routes: [ ???{ ?????path: ‘/foo‘, ?????component: Foo, ?????beforeEnter: (to, from, next) => { ???????// ... ?????} ???} ?]})

2、组件内的守卫

最后,你可以在路由组件内直接定义以下路由导航守卫

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

   beforeRouteEnter 守卫 不能 访问 this,因为守卫在导航确认前被调用,因此即将登场的新组件还没被创建。

     不过,你可以通过传一个回调给 next来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数。

beforeRouteEnter (to, from, next) { ?next(vm => { ???// 通过 `vm` 访问组件实例 ?})}

   注意 beforeRouteEnter 是支持给 next 传递回调的唯一守卫。对于 beforeRouteUpdate 和 beforeRouteLeave来说,this 已经可用了,所以不支持传递回调,因为没有必要了。

beforeRouteUpdate (to, from, next) { ?// just use `this` ?this.name = to.params.name ?next()}

  这个离开守卫通常用来禁止用户在还未保存修改前突然离开。该导航可以通过 next(false) 来取消。

beforeRouteLeave (to, from , next) { ?const answer = window.confirm(‘你确定要退出吗‘) ?if (answer) { ???next() ?} else { ???next(false) ?}}

下面用一个小案例说明:

<script src="https://unpkg.com/vue/dist/vue.js"></script><script src="https://unpkg.com/vue-router/dist/vue-router.js"></script><div id="app"> ???<button type="button" @click="fooClick">/user/foo</button> ???<button type="button" @click="profileClick">/user/foo/profile</button> ???<button type="button" @click="postsClick">/user/foo/posts</button> ???<router-view></router-view></div><script> ???//定义了三个组件 ???const UserHome = { template: ‘<div>Home</div>‘} ?????const UserProfile = {template: ‘<div>Profile</div>‘ } ????const UserPosts = {template: ‘<div>Posts</div>‘} ???????????//匹配了三个路由 ?????const router = new VueRouter({ ???????????routes: [{ ???????????????path: ‘/user/foo‘, ???????????????component: UserHome, ???????????????beforeEnter: (to, from, next) => { ???????????????????console.log(‘进入UserHome组件‘); ???????????????????next(); ???????????????} ???????????}, { ???????????????path: ‘/user/foo/profile‘, ???????????????component: UserProfile, ???????????????beforeEnter: (to, from, next) => { ???????????????????console.log(‘进入profile组件‘); ???????????????????next(); ???????????????} ???????????}, { ???????????????path: ‘/user/foo/posts‘, ???????????????component: UserPosts, ???????????????beforeEnter: (to, from, next) => { ???????????????????console.log(‘UserPosts组件‘); ???????????????????//这里设置flase说明就算路径为‘/user/foo/posts‘,也不会进入UserPosts组件 ???????????????????next(false); ???????????????} ???????????}] ???????}) ???????//设置全局导航守卫 ???????router.beforeEach((to, from, next) => { ???????console.log(‘进入全局守卫导航‘); ???????console.log(‘进入路由路径:‘ + to.path); ???????console.log(‘离开路由路径:‘ + from.path); ???????next(); ???}) ???const app = new Vue({ ???????el: ‘#app‘, ???????router, ???????data: { ???????????foo: ‘/user/foo‘, ???????????profile: ‘/user/foo/profile‘, ???????????posts: ‘/user/foo/posts‘ ???????}, ???????methods: { ???????????fooClick: function(event) { ???????????????this.$router.push({ ???????????????????path: this.foo ???????????????}); ???????????}, ???????????profileClick: function(event) { ???????????????this.$router.push({ ???????????????????path: this.profile ???????????????}); ???????????}, ???????????postsClick: function(event) { ???????????????this.$router.push({ ???????????????????path: this.posts ???????????????}); ???????????} } ???????})</Script>

效果:

通过上面可以得出以下结论:

     1、全局守卫会比组件守卫先执行

     2.全局守卫第一次加载页面to和from路径都是“/”

     3.每一次路径改变都会调用全局组件,路径不变是不会调用全局守卫,也不会在调用组件守卫

     4.我在/user/foo/posts路径设置为next(flase)是,当点击它是并没有跳转UserPosts组件,页面显示的还是profile说明跳转失败。

二、路由元信息(meta)

    为什么会有路由元信息这个东西?首先要知道它到底有什么作用。

   我们在做网站登录验证的时候,可以使用到beforeEach 钩子函数进行验证操作,如下面代码 ,如果页面path为’/goodsList’,那么就让它跳转到登录页面,实现了验证登录。

router.beforeEach((to, from, next) => { ?if (to.path === ‘/goodsList‘) { ???next(‘/login‘) ?} else ????next()})

 如果需要登录验证的网页多了怎么办?

1.这里是对比path。如果需要验证的网页很多,那么在if条件里得写下所有的路由地址,将会是非常麻烦的一件事情。

2.因为路由是可以嵌套的。有’/goodsList’,那么可能会有’/goodsList/online’,再或者还有’/goodsList/offline’、’/goodsList/audit’、’/goodsList/online/edit’等等。

如果像刚才例子中这样对比(to.path === ‘/goodsList’),就非常单一,其他的路径压根不会限制(验证)到,照样能正常登陆!因为每个to.path根本不一样。

我们所理想的就是把’/goodsList’限制了,其他所有的以’/goodsList’开头的那些页面都给限制到!

to Route: 即将要进入的目标 路由对象 
我们打印一下to

它有很多属性,有 
  - fullPath 
  - hash 
  - matched 
  - meta 
  - name 
  - params 
  - path 
  - query

其中有个属性,matched,就是匹配了的路由,我们打印出来,这个是个数组。它的第一项就是{path: “/goodslist”},一直到最为具体的当前path (例如:{path: “/goodslist/online/edit”})

这里可以循环matched这个数组,看每一项的path 有没有等于’/goodsList’,只要其中一个有,那么就让它跳转到登录状态

router.beforeEach((to, from, next) => { ?if (to.matched.some(function (item) { ???return item.path == ‘/goodslist‘ ?})) { ???next(‘/login‘) ?} else ????next()})

那么这里只是对goodsList进行验证判断,且限制的还是path,就相当于把goodsList下面都给限制了,但有些东西是不需要登陆直接可以显示在页面的,比如:资讯信息,广告信息。这么做不就不可行了。用path来做限制似乎有点不好用。轮到主角登场了

meta字段(元数据)

直接在路由配置的时候,给每个路由添加一个自定义的meta对象,在meta对象中可以设置一些状态,来进行一些操作。用它来做登录校验再合适不过了

{ ?path: ‘/actile‘, ?name: ‘Actile‘, ?component: Actile, ?meta: { ???login_require: false ?},},{ ?path: ‘/goodslist‘, ?name: ‘goodslist‘, ?component: Goodslist, ?meta: { ???login_require: true ?}, ?children:[ ???{ ?????path: ‘online‘, ?????component: GoodslistOnline ???} ?]}

这里我们只需要判断item下面的meta对象中的login_require是不是true,就可以做一些限制了

router.beforeEach((to, from, next) => { ?if (to.matched.some(function (item) { ???return item.meta.login_require ?})) { ???next(‘/login‘) ?} else ????next()})

     meta还可以放其它信息,比如可以存储该路由相关信息(例如:设置每个路由的title,取路由的title设置为选项卡的标题)

{ ?????path: ‘/router2‘, ?????name: ‘router2‘, ?????component:router2, ?????meta:{ ???????title:"积分模块" ?????} ???}
// 全局前置守卫router.beforeEach((to,from,next) => { ???console.log(to); ???console.log(from); ???if(to.meta.title) { ?????document.title = to.meta.title; ???} else { ?????document.title = ‘我是默认的title‘ ???} ???next();});

想太多,做太少,中间的落差就是烦恼。想没有烦恼,要么别想,要么多做。上尉【1】

VueJs(12)---vue-router(导航守卫,路由元信息)

原文地址:https://www.cnblogs.com/qdhxhz/p/9016792.html

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved