vue之移动端的页面在返回时记住操作的位置,提供滑动动画效果

1、在main.js中添加

import ctpRouter from '@/ares-ui-extend/CtpRouter';
Vue.use(ctpRouter, router);

2、添加相应的代码

在src的目录下添加 ares-ui-extend 的文件夹

 ares-ui-extend 文件夹的下面添加CtpRouter,CtpRouter下面为:

 ctp-router.css内容为:

/*
动画样式
*/
.fade-enter-active, .fade-leave-active {
  transition: opacity .5s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
  opacity: 0;
}

.sild-leave-active {
  transition: all 1.5s;
}
 .sild-enter-active  {
  transition: all .4s;
}

/* .sild-enter /* .fade-leave-active below version 2.1.8  {
  transform:translate3d(100%, 0, 0);
}
.sild-leave-to /* .fade-leave-active below version 2.1.8  {
  transform:translate3d(-100%, 0, 0);
} */

.sild1-leave-active  {
  transition: all .4s;
}
.sild1-enter-active {
  transition: all .4s;
}
/*
.sild1-enter /* .fade-leave-active below version 2.1.8  {
  transform:translate3d(-100%, 0, 0);
}
.sild1-leave-to /* .fade-leave-active below version 2.1.8  {
  transform:translate3d(100%, 0, 0);
}
*/

.sild-enter /* .fade-leave-active below version 2.1.8 */ {
  transform: translate3d(2rem, 0, 0);
  opacity: 0;
}
.sild-leave-to /* .fade-leave-active below version 2.1.8 */ {
  transform: translate3d(-2rem, 0, 0);
  opacity: 0;
}

.sild1-enter /* .fade-leave-active below version 2.1.8 */ {
  /* transform: translate3d(-2rem, 0, 0); */
  opacity: 0;
}
.sild1-leave-to /* .fade-leave-active below version 2.1.8 */ {
  transform: translate3d(2rem, 0, 0);
  opacity: 0;
}

index.js 的内容为:

/*
拦截重写vue路由,提供滑动动画效果,记录页面位置
*/
import Nav from './nav';
import './ctp-router.css';

function CtpRouter(Vue) {
  Vue.prototype.$ctpRouter = {
    tn: 'slide', // 动画名
    keepAlives: [], // keepAlive存储
  };

  this.stack = [];
  this.PAGEKEY = new Date().getTime();

  this.createPageKey = () => {
    this.PAGEKEY += 1;
    return this.PAGEKEY.toString();
  };

  this.findStackIndex = pageKey => this.stack.findIndex(item => item === pageKey);

  this.pushStack = (pageKey) => {
    const index = this.findStackIndex(pageKey);
    this.stack.slice(0, index + 1);
    this.stack.push(pageKey);
  };

  this.clearStack = (pageKey) => {
    if (pageKey) {
      for (let i = 0; i < this.stack.length; i += 1) {
        if (pageKey === this.stack[i]) {
          this.stack.splice(i, 1);
          break;
        }
      }
    } else {
      this.stack = [];
    }
  };

  this.rewriteRouter = (router) => {
    ['push', 'replace'].forEach((method) => {
      const func = router[method].bind(router);
      router[method] = (location, onComplete, onAbort) => {
        const obj = {};
        if (typeof location !== 'object') {
          obj.path = location;
        } else {
          Object.assign(obj, location);
        }
        if (!obj.query) {
          obj.query = {};
        }
        if (method === 'push') {
          obj.query.$page_key = this.createPageKey();
          this.pushStack(obj.query.$page_key);
        }
        if (method === 'replace') {
          obj.query.$replace = true;
        }
        func(obj, onComplete, onAbort);
      };
    });
  };

  this.setKeepAlive = (router) => {
    const routes = router.options.routes;
    if (routes && routes.length > 0) {
      routes.forEach((route) => {
        const meta = route.meta;
        if (meta && meta.keepAlive) {
          Vue.prototype.$ctpRouter.keepAlives.push(route.name);
        }
      });
    }
  };

  this.setTransition = (from, to) => {
    const fromIndex = this.findStackIndex(from.query.$page_key);
    const toIndex = this.findStackIndex(to.query.$page_key);
    if (fromIndex < toIndex) { // enter
      Vue.prototype.$ctpRouter.tn = 'sild';
    } else if (fromIndex > toIndex) { // leave
      Vue.prototype.$ctpRouter.tn = 'sild1';
    } else {
      Vue.prototype.$ctpRouter.tn = 'none'; // replace则不做任何动画
    }
  };

  this.storeFromScrollTop = (vm, from) => {
    const scrollContainer = vm.$refs.scrollContainer;
    if (scrollContainer && from.meta) {
      from.meta.scrollTop = scrollContainer.scrollTop;
    }
  };

  // 跳转时,设置to页面的已记录的高度(来自于storeFromScrollTop)
  this.reStoreToScrollTop = (vm, to) => {
    const scrollContainer = vm.$refs.scrollContainer;
    if (scrollContainer && to.meta && to.meta.scrollTop) {
      scrollContainer.scrollTop = to.meta.scrollTop;
    }
  };
}
export default (Vue, router) => {
  const ctpRouter = new CtpRouter(Vue);
  ctpRouter.setKeepAlive(router);
  ctpRouter.rewriteRouter(router);

  Vue.component(Nav.name, Nav);

  Vue.mixin({
    beforeRouteEnter(to, from, next) {
      if (!to.query.$page_key) { // 首次进入的时候没有$page_key
        const obj = Object.assign({}, to);
        obj.replace = true;
        obj.query.$page_key = ctpRouter.createPageKey();
        ctpRouter.pushStack(obj.query.$page_key);
        next(obj);
      } else {
        next((vm) => {
          ctpRouter.reStoreToScrollTop(vm, to);
        });
      }
    },
    beforeRouteLeave(to, from, next) {
      if (to.query.$replace) {
        to.query.$page_key = from.query.$page_key;
        delete to.query.$replace;
        const obj = Object.assign({}, to);
        obj.replace = true;
        next(obj);
        return;
      }
      ctpRouter.storeFromScrollTop(this, from); // 记录离开时的位置
      ctpRouter.setTransition(from, to); // 设置动画
      next();
    },
  });
};

nav.vue的内容为:

<template>
  <transition :name="$ctpRouter.tn">
    <keep-alive :include="$ctpRouter.keepAlives">
      <slot></slot>
    </keep-alive>
  </transition>
</template>

<script>
export default {
  name: 'ctp-router',
};
</script>

3、用法:在定义路由的时候在meta中添加 keepAlive 的布尔值,为true则启用缓存记录页面位置,为false则不启用缓存。例子:

{
    path: '/Home/notice/notice_center',
    name: 'notice_center',
    component: resolve => require(['@/pages/Home/notice/notice_center.vue'], resolve),
    meta: {
        moduleName: 'notice_center',
        title: '消息中心', keepAlive: false   
    },
    routerLevel: 2,
}

4、总结:

ares-ui-extend 和 CtpRouter 这俩文件夹的名字,自己可以随便更改,ares-ui是公司自有的框架,所以最好是起一个别的名字。其他代码可以参考着拿来直接用。

目的就是缓存组件数据,返回上一页的时候,记录之前的操作位置,这样统一封装之后,移动端的项目有这样的需求,就直接改变路由里面meta的keepAlive值即可。

posted @ 2024-05-20 11:29  smil、梵音  阅读(43)  评论(0编辑  收藏  举报