vue-router如何判断浏览器前进后退按钮,调用不同的transition

    <transition name="fade" >
      <router-view name="a" class="template"></router-view>
    </transition>

简单的一个路由,有一个动画。

现在我用的是fade这个动画,

我现在想要浏览器前进或者后退调用不同的动画应该怎么做。。

阅读 39.6k
8 个回答

图片描述

网上搜索的方法都有点问题:前进到存在的路由将被识别为返回行为
https://github.com/zack24q/vu...

我的方法是:

  • 定义个全局变量pageDirection(这里用store),而且默认值是'slide-right',表示返回状态;

  • document事件委托给<a/>标签,点击时说明触发了路由这个时候设置pageDirection='slide-left';

  • 在路由钩子routeEnter里,设置回pageDirection='slide-right'。

关键代码

  • 根组件App.vue

<template>
  <div id="app">
      <ul>
        <li><router-link to="/">/home</router-link></li>
        <li><router-link to="/default">/default</router-link></li>
        <li><router-link to="/foo">/foo</router-link></li>
        <li><router-link to="/bar">/bar</router-link></li>
      </ul>
      <p>{{pageDirection}}</p>
      <transition :name="pageDirection" @after-enter="afterEnter">
        <router-view class="child-view"></router-view>
      </transition>
  </div>
</template>
<script>
import {mapState, mapMutations} from 'vuex';
export default {
  name: 'app',
  created(){
    console.log(this);
  },
  computed:{
    ...mapState([
      'pageDirection'
    ])
  },
  methods:{
    ...mapMutations([
      'afterEnter'
    ])
  }
}
</script>
<style>
.fade-enter-active, .fade-leave-active {
  transition: opacity .5s ease;
}
.fade-enter, .fade-leave-active {
  opacity: 0
}
.child-view {
  position: absolute;
  transition: all .4s cubic-bezier(.55,0,.1,1);
}
.slide-left-enter, .slide-right-leave-active {
  opacity: 0;
  -webkit-transform: translate(30px, 0);
  transform: translate(30px, 0);
}
.slide-left-leave-active, .slide-right-enter {
  opacity: 0;
  -webkit-transform: translate(-30px, 0);
  transform: translate(-30px, 0);
}
</style>
  • 入口文件main.js

import Vue from 'vue';
import App from './App';
import router from './router';
import store from './store/';

Vue.config.productionTip = false;


/* eslint-disable no-new */
new Vue({
    el: '#app',
    router,
    store,
    template: '<App/>',
    components: { App },
    created() {
        document.addEventListener('mousedown', (e) => {
            let state = this.$store.state;
            const target = e.target;
            if (target.nodeName === 'A' &&
                target.getAttribute('href').substring(0, 2) === '#/') { //点击路由链接说明激活路由
                state.pageDirection = 'slide-left';
            }
        })
    }
});
  • store/index.js

import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export default new Vuex.Store({
    state: {
        pageDirection: 'fade'
    },
    mutations: {
        afterEnter: (state) => {
            state.pageDirection = 'slide-right';
        }
    }
});

希望有人给出更加好的方法。

最后我还是用这种方法,样式还是用原来的

export default new Vuex.Store({
    state: {
        count: 1,
        pageDirection: 'fade',
        routeChain:[]
    },
    mutations: {
        addRouteChain(state, route){
            state.routeChain.push(route);
        },
        popRouteChain(state){
            state.routeChain.pop();
        },
        setPageDirection(state, dir){
            state.pageDirection = dir;
        }
    }
});
router.beforeEach((to, from, next) => {
    //定义一个可以记录路由路径变化的数组,这里用在vuex,其实也可以用sessionStorage,或者在window.routeChain等变量
    //不一定要用到vuex
    let routeLength = store.state.routeChain.length;
    if (routeLength === 0) {
        store.commit('setPageDirection', 'fade');
        if (to.path === from.path && to.path === '/') {
            //当直接打开根路由的时候
            store.commit('addRouteChain', to);
        } else {
            //直接打开非根路由的时候其实生成了两个路径,from其实就是根路由
            store.commit('addRouteChain', from);
            store.commit('addRouteChain', to);
        }
    } else if (routeLength === 1) {
        store.commit('setPageDirection', 'slide-left');
        store.commit('addRouteChain', to);
    } else {
        let lastBeforeRoute = store.state.routeChain[routeLength-2];
        if (lastBeforeRoute.path === to.path) {
            store.commit('popRouteChain');
            store.commit('setPageDirection', 'slide-right');
        } else {
            store.commit('addRouteChain', to);
            store.commit('setPageDirection', 'slide-left');
        }
    }
    next();
});

问题是在当前目录点击上一个页面的时候,会当作返回。这个问题,好像也不是问题。

<!-- 使用动态的 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'

}
}
https://github.com/vuejs/vue-...

我已经做出了这样的效果
用的确实是楼上监听 $route 的方法
但是由于我的view都处于同级,并不能使用楼上的方法
我的组件 都是

/aaa/id   /bbb/id

这种形式

所以我只能在 router-link 里面加入一个key value 是timestamp
然后在watch $route 的时候对比 timestamp

watch: {
    '$route' (to, from) {
      console.log('前一页 from = ' + from.query.key)
      console.log('准备进入的页面是  to = ' + to.query.key)
      if (from.query.key) {
        if (to.query.key > from.query.key) {
          this.transitionName = 'slide-fade'
        } else {
          this.transitionName = 'slide-left'
        }
      } else {
        this.transitionName = 'slide-fade'
      }
    }
  }

view 页面必须要有一个 computed

computed: {
      key () {
        return (new Date()).valueOf()
      }
    }

router link 必须要携带 query

 <router-link :to="{ name: 'user', params: { id: list.user_id },query: {key:key}}">    
 </<router-link>

效果可以实现 ,但是会增加url 长度

如果有人有其他方法实现,希望能提出

简单的说,就是自己维护一份浏览记录,每次路由切换时跟浏览记录对比下就知道是前进还是后退了。
更详细的请移步基于vue的移动web app页面缓存解决方案

可以参考下vue-navigation的实现方式,现在更新到1.0了,支持重复的路由出现在路由栈中了。

VueRouter.prototype.goBack = function () {  //重点,给VueRoute添加一个goBack方法,用于记录路由的前进后退状态 this.isBack = true 
  this.isBack = true
  window.history.go(-1)
}

返回就调用这个函数

<template>
  <div>
    <transition :name="transitionName">   //动态绑定路由动画
    <router-view class="Router"></router-view>
    </transition>
</div>
</template>

<script>
export default {
  data() {
    return {
      transitionName: ‘slide-right‘  // 默认动态路由变化为slide-right
    }
  },
  watch: {
   ‘$route‘ (to, from) {
    let isBack = this.$router.isBack  //  监听路由变化时的状态为前进还是后退
      if(isBack) {
        this.transitionName = ‘slide-right‘
      } else {
             this.transitionName = ‘slide-left‘
     }
  this.$router.isBack = false
  }
  }
 }
</script>

<style>
.Router {
position: absolute;
width: 100%;
transition: all .8s ease;
top: 40px;
}

.slide-left-enter,
.slide-right-leave-active {
opacity: 0;
-webkit-transform: translate(100%, 0);
transform: translate(100%, 0);
}

.slide-left-leave-active,
.slide-right-enter {
opacity: 0;
-webkit-transform: translate(-100%, 0);
transform: translate(-100% 0);
}
</style>
新手上路,请多包涵

router.go = function (n) { // 后退。

this.history.go(n);
this._recede = true;

};

watch: {

$route(to) {
  this.transitions = this.$router._recede ? "rightLeft" : "about";
  this.$router._recede = false;
  return false;
}

}

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏