我是帅帅的玉米

MealieLin

轻撩衣袖,笑对斑驳月光;持一抹惆怅,倒问沧澜;任我红袖舞乱,红尘依旧百转千回化成殇!


【vue-router②】使用导航守卫控制页面前进刷新,后退缓存

2017, Nov 02       阅读:

之前给大家分享了利用keep-alive进行缓存你想要的页面,然后到后面会出现这样的问题: 我有三个组件A(组件)、B(A中的弹框)、C(组件),其实算是两个组件,一个弹框,现在他们的关系是这样的:

点击A(li循环列表组件)中某个功能,弹出了B(弹框-表格),然后在B(弹框)点击连接跳转到C(组件)。 然后我想要实现A(li循环列表组件)缓存,B(弹框-表格)根据A的传参实时刷新,C(组件)根据B的传参实时刷新,A->B->C。 接下来返回依次从C->B->A,如下图:

vue-router2(1)

1、B是一个弹框,和A处于同一个组件,从C返回要看到B的话,就要实现A缓存,即C返回A的时候A没刷新还保持弹框不变就可以实现C是退回B,这个用前面说的keep-alive就可以实现。

2、这时候从B->A(我们这边退回按钮设置关闭弹框是可以实现B->A的),点击的是浏览器或者手机的回退键,就会发现,并没有实现这一步,而是B直接退到A的前一页,因为系统的回退键记录的是历史路由,而B和A本身就是一个路由,所以就会出现这种情况。 这时候的解决办法就是:判断路由离开前,B弹框是否打开,若是打开就先关闭弹框,不允许路由跳转,所以就可以造成B回退到A的假象。这时候利用的是beforeRouteLeave钩子。实现如下:

beforeRouteLeave(to,from,next) {
    //B是B弹框的v-model值
    if (this.B) {
      this.B= false;
      next(false);
    } else {
      next();
    }
}

3、然后接下来你就会发现另一个问题,就是B->C的时候,因为B是打开的,上面的判断就会造成B无法跳转到C,但是没设置上面的代码,就会造成C回退的时候,要么是到C->A(A不设缓存,实时刷新)->A前面的页面,要么C->B(A设缓存,不刷新就保持B)->A前面的页面,无论是那种情况都不是我们想要的。 解决:还是使用beforeRouteLeave,再加一层判断,当路由跳转的目标是C的时候,next设为true,若是其他跳转则设为false。

(1)判断目标路由是C的时候,保持B为true,这样C->B,

(2)当B后退的时候,判断B打开,则先关闭B,不后退,这样就能B->A

(3)A再回退的时候,B已经为false,所A就可以再返回到它的上一级。

 beforeRouteLeave(to,from,next) {
      /*to:目标路由
      * from:当前要离开的路由
      * */
      if(to.name === "C"){
        if(this.B){
          this.B= true;
          next();
        } else{
          next();}
      }else {
        if (this.B) {
          this.B= false;
          next(false);
        } else {
          next();
        }
      }
    },

这里就可以实现我要的回退顺序及效果。

说到beforeRouteLeave,就不得不跟大家提一下v-router的导航守卫,可参考官方文档

现在我来说下我对于组件内的守卫的一个理解。共有三个:

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`
  }
}

三者都能接收三种参数:to, from, next

vue-router2(2)

顾名思义,

beforeRouteEnter :表示在进入当前组件前的一个操作,它执行顺序是很靠前的,而其中next的回调勾子的函数,执行则非常靠后,在mounted之后!!

我们通常是在beforeRouteEnter中加载一些首屏用数据,待数据收到后,再调用next勾子,通过回调的参数vm将数据绑定到实例上。

因此,请注意next的勾子是非常靠后的。

beforeRouteEnter(to, from, next) {
    next(vm => {
        if(to.name == '目标路由名称'){
            //vm.fetchData()
        }else{
            //vm.fetchData()
        }
    })
}

beforeRouteUpdate :表示在当前组件改变之前,这个还没用过,具体我也不太清楚里面的情况,后面用到再做介绍。

beforeRouteLeave :表示在当前组件离开之前,这个就是我的最爱了,现在对于组件的状态控制,我可都是依赖它的,像上面提到的控制弹框和跳转。

本文在segmentfault的地址