16

之前给大家分享了利用keep-alive进行缓存你想要的页面,然后到后面会出现这样的问题:
我有三个组件A(组件)、B(A中的弹框)、C(组件),其实算是两个组件,一个弹框,现在他们的关系是这样的:
点击A(li循环列表组件)中某个功能,弹出了B(弹框-表格),然后在B(弹框)点击连接跳转到C(组件)。
然后我想要实现A(li循环列表组件)缓存,B(弹框-表格)根据A的传参实时刷新,C(组件)根据B的传参实时刷新,A->B->C。
接下来返回依次从C->B->A,如下图:

clipboard.png

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

clipboard.png

顾名思义,
beforeRouteEnter :表示在进入当前组件前的一个操作,它执行顺序是很靠前的,而其中next的回调勾子的函数,执行则非常靠后,在mounted之后!!
我们通常是在beforeRouteEnter中加载一些首屏用数据,待数据收到后,再调用next勾子,通过回调的参数vm将数据绑定到实例上。
因此,请注意next的勾子是非常靠后的。

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

beforeRouteUpdate :表示在当前组件改变之前,这个还没用过,具体我也不太清楚里面的情况,后面用到再做介绍。
beforeRouteLeave :表示在当前组件离开之前,这个就是我的最爱了,现在对于组件的状态控制,我可都是依赖它的,像上面提到的控制弹框和跳转。


如果觉得我的文章对你有用,请随意赞赏

你可能感兴趣的

太羽 · 2018年01月06日

(1)如果B也是一个路由呢(弹窗内容为:<route-view></route-view>),点击A的按钮,打开弹窗,跳转到B的路由,此时B的内容就会渲染为路由所指向的内容
(2)如果A组件内有两个带有不同参数的按钮1和按钮2,都是打开B(也就是公用一个组件)有没有考虑过这两个参数能否都传过来?

PS:解释下为什么B中的内容要使用路由渲染:A路由中的弹窗B内容很多的话(不仅仅是一个表格),页面就很长很复杂不好控制,也不利于复用,如果A中有很多弹窗的话也需要使用路由渲染B中的内容
https://segmentfault.com/q/10... 这是我在制作过程中遇到的问题,有兴趣可以思考下

回复

0

对的,你这个也是另一种情况的,你这种情况就是要考虑怎么缓存B之后怎么通过路径的来回判断B是要刷新还是继续保持缓存。

我是帅帅的玉米 作者 · 2018年01月08日
0

@我是帅帅的玉米 最后通过created和beforeRouteUpdate两个钩子解决的,目前没有返回刷新的需求,我只解决了共用组件接收不同参数的问题,如果项目有这方面的需求了按照您这篇文章的做法也可以很简单的实现。

太羽 · 2018年01月08日
载入中...