首页 > Web开发 > 详细

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

时间:2018-05-09 22:15:14      阅读:827      评论:0      收藏:0      [点我收藏+]

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

(0)
(1)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!