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

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

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

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

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

阅读 23.3k
评论
    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-...

      评论 赞赏
        channg
        • 123

        我已经做出了这样的效果
        用的确实是楼上监听 $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>
            评论 赞赏
              评论 赞赏
                wuxiantiant
                • 2
                • 新人请关照

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

                }

                评论 赞赏

                  可以在beforeEach将每一次的path和访问深度记录到sessionStorage

                  sessionStorage.setItem(to.path, deep)

                  只要在之前判断一下sessionStorage里面有无to.path的记录

                  • 没有则deep+1,记录to.path的记录到sessionStorage,设置前进动画方向

                  • 有者deep-1,删除from.path的记录,在记录to.path的记录到sessionStorage,设置后退

                  该答案已被忽略,原因:

                  评论 赞赏
                    撰写回答

                    登录后参与交流、获取后续更新提醒