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值即可。