Vue Router 过渡效果

1,218 阅读2分钟

问题描述:移动端页面切换往往需要左滑、右滑的过渡效果。

Vue Router的官网也有相关过渡动效的介绍。以下为官网的例子

<!-- 使用动态的 transition name -->
<transition :name="transitionName">
  <router-view></router-view>
</transition>
// 接着在父组件内
// watch $route 决定使用哪种过渡
watch: {
  '$route' (to, from) {
    const toDepth = to.path.split('/').length
    const fromDepth = from.path.split('/').length
    this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'
  }
}

具体代码 移步这里

这种实现方式并不是我需要的。因为我的路由跳转可能并不都是父子关系。我接着看官方文档,刚好看到有一个叫 滚动行为 的介绍。这是一个在创建Router实例时提供的方法--scrollBehavior该方法原本是用来记录路由滚动位置的,但我觉得它刚好可以来帮我判断路由是在前进还是后退。

scrollBehavior 方法接收 tofrom 路由对象。第三个参数 savedPosition 当且仅当 popstate 导航 (通过浏览器的 前进/后退 按钮触发) 时才可用。

const router = new VueRouter({
  routes: [...],
  scrollBehavior (to, from, savedPosition) {
    // return 期望滚动到哪个的位置
  }
})

这个方法返回滚动位置的对象信息,长这样:

{ x: number, y: number }
{ selector: string, offset? : { x: number, y: number }} //(offset 只在 2.6.0+ 支持)

按照官网的意思,当页面返回时,第三个参数savedPosition会记录上一个页面的滚动位置的对象信息。而当页面前进时,savedPosition则会返回一个null。这就刚好可以为我所用了。既如果 savedPosition 为空,我们认为页面是在前进,否则认为是在后退。我们可以通过管理一个Vuex的全局变量,来表示页面的前进、后退情况。

const router = new VueRouter({
  routes,
  scrollBehavior(to, from, savedPosition) {
    if (savedPosition) {
      store.commit('PageForward');
      return savedPosition
    } else {
      store.commit('pageBack');
      return { x: 0, y: 0 }
    }
  }
});

vuex代码:

  state: {
    isBack:false
  },
  mutations: {
    pageBack(state){
      state.isBack = true
    },
    PageForward(state){
      state.isBack = false
    }
  },

App.vue代码:

<transition :name="transitionName">
  <router-view v-if="!$route.meta.keepAlive" />
  <keep-alive>
    <router-view v-if="$route.meta.keepAlive" />
  </keep-alive>
</transition>

js:

  computed: {
    transitionName() {
      return this.$store.state.isBack?'slide-right':'slide-left'
    }
  },

ps.由于官网并未提及 scrollBehavior的此种用途,网上我也没见过这种用法,所以可能会存在一定问题,欢迎指出