详情返回定位
本文中的详情返回定位,只针对于mand-mobile组件的运用中的一些处理,仅做学习记录。其他组件可能无需考虑auto-reflow属性的影响。
使用场景: 使用mand-mobile组件实现的列表的分页展示,大概的HTML代码如下,为了实现点击单行数据,跳转详情页,从详情也返回后,页面不刷新,位置仍然为跳转前的显示位置。
//滚动区域
<md-scroll-view class="scroll" ref="scrollView" v-show="!isNoData"
:scrolling-y="true" :scrolling-x="false" :auto-reflow="autoReflow" //注意点注意点 后面会提到
@scroll="onScroll" @endReached="endReached" @refreshing="onRefreshing">
//列表区域
<md-check-group v-model="orderSelecteds" ref="group">
<div class="orderList" v-for="(order, index) in orderList":key="order.tradeId">
<div class="orderDetail" @click="orderDetail(order.tradeId)">
//列表数据渲染 省略
</div>
</div>
</md-check-group>
//底部加载更多 触发分页查询
<md-scroll-view-more slot="more" :is-finished="isFinished" ></md-scroll-view-more>
//顶部下拉刷新
<md-scroll-view-refresh slot="refresh"
slot-scope="{ scrollTop, isRefreshActive, isRefreshing }"
:scroll-top="scrollTop" :is-refreshing="isRefreshing" :is-refresh-active="isRefreshActive">
</md-scroll-view-refresh>
</md-scroll-view>
网上提供的方法,大概分为3种:
- 定义一个变量
- 利用local缓存
- 使用vuex
思路: 在触发详情跳转前,存储当前的ScrollTop,在返回列表页时,给页面高度重新赋值。
方法1 利用beforeRouteLeave、beforeRouteEnter
在离开页面触发beforeRouteLeave时,记录当前页面滚动高度,返回页面触发beforeRouteEnter时,给document.querySelector(’.scroll’).scrollTop 重新赋值。
其中,滚动的高度可以通过(1)localStorage缓存记录,也可以通过(2)vuex commit触发改变存在state里的高度的值
beforeRouteLeave(to, from, next) {
if (to.name === "order_detail") {
let scrollTop = this.$refs.scrollView.scrollY;
console.log(scrollTop);
//1.利用localStorage 存滚动距离顶部的高度
localStorage.setItem('scrollY', scrollTop);
//2.利用vuex 触发setScrollTop事件改变 scrollTop
this.$store.commit("omsOnline/setScrollTop", scrollTop);
} else {
from.meta.keepAlive = false;
}
next();
},
beforeRouteEnter(to, from, next) {
//因为当钩子执行前,组件实例还没被创建
// vm 就是当前组件的实例相当于上面的 this,所以在 next 方法里你就可以把 vm 当 this 来用了。
next((vm) => {
//1.利用 localStorage 取缓存里的值
let scrollY = localStorage.getItem('scrollY');
//2.利用vuex 取之前存的_scrollTop值
let scrollY = vm.$store.getters["omsOnline/_scrollTop"];
//scrollTo 不生效 不知道为啥 hhhh
// vm.$refs.scrollView.scrollTo(0, scrollY, false);
利用document选择器取值,可以实现
document.querySelector('.scroll').scrollTop = scrollY;
});
},
以上的beforeRouteEnter 可以使用activated替代。
activated() {
this.$nextTick(() => {
//1.利用 localStorage 取缓存里的值
let scrollY = localStorage.getItem('scrollY');
//2.利用vuex 取之前存的_scrollTop值
let scrollY = vm.$store.getters["omsOnline/_scrollTop"];
document.querySelector('.scroll').scrollTop = scrollY;
});
},
用了上面的方法一直疑惑为什么没法通过this.$refs..scrollView.scrollTo(0, scrollY)
或 this.$refs.scrollView.scrollY(scrollY)
来改变滚动的位置,始终没有效果,想着可能是当前的mand-mobile组件有其他的事件影响了,也可能是层级有问题吧。
后来研究mand-mobile 组件中ScrollView的一些内置方法,想到可能是这个方法影响了,详情页返回是,内容发生变化,自动滚动至页面最上方。
最初auto-reflow的值为true,后来改为了false,果然可以定位到原来数据的位置了。
但是又引发了另一个问题,因为数据是分页的,并且可以进行数据的过滤筛选,加载分页数据后,再次触发筛选,页面下方会出现空白,没办法将筛选出来的数据正确的从顶部开始显示,也没办法及时的显示出‘加载更多’的字样,从而出现断层的空白页。
所以auto-reflow不能写死,需要动态控制。在触发分页时,将auto-reflow设为false,保证详情返回的定位正确,在触发筛选前,将auto-reflow设为true,保证页面滚动区域自动重置。
//下拉加载更多
endReached() {
if (this.isFinished) {
return;
}
//下拉之后,自动重置滚动区域 设为false 否则详情返回会自动回到顶部
this.autoReflow = false;
this.query.pageIndex++;
this.getOrder();
},
//获取默认参数
getDefaultParam() {
//过滤筛选时,自动重置滚动区域 设为 true, 否则下拉会出现空白
this.autoReflow = true;
this.$refs.scrollView.scrollTo(0, 0);
//------------
//省略其他内容
//------------
}
对于记录和定位,我是用的是最偷懒的一种方法,定义一个变量scroll ,暂存页面内滚动后距离顶部的距离。
在跳转详情事件中:记录scroll
orderDetail(tradeId) {
//获取当前滚动的高度
let scrollTop = this.$refs.scrollView.scrollY;
//赋值给定义的变量,暂存
this.scroll = scrollTop;
//跳转详情页面
this.$router.push({
path: "/oms-online/orderDetail",
query: {
tradeId: tradeId,
},
});
},
activated() {
this.$refs.scrollView.scrollY = this.scroll;
},
返回顶部
既然做了下拉返回的功能,顺便做了个‘返回顶部’的小功能。
父组件:
//返回顶部子组件
<jk-back-top v-if="isShowBack" :scrollTop="scrollTop"></jk-back-top>
通过isShowBack判断是否显示返回顶部的图标,这时需要监听滚动区域距离顶部的高度。
md-scroll-view class="scroll" ref="scrollView"
:scrolling-y="true" :scrolling-x="false :auto-reflow="autoReflow"
@scroll="onScroll" //滚动事件
>
滚动事件记录scrollTop 高度
//滚动事件
onScroll({scrollLeft, scrollTop}) {
this.scrollTop = scrollTop;
},
监听scrollTop的最新值,到大于200时,显示‘返回顶部’的图标
watch: {
scrollTop(top) {
if(top > 200){
this.isShowBack = true;
} else {
this.isShowBack = false;
}
}
},
子组件:
<template>
<div>
<img src="@/utils/oms-online/images/backTop.png" alt="" @click="backTop" />
</div>
</template>
<script>
export default {
components: {},
data() {
return {
scrollTrigger: false,
};
},
props: {
scrollTop: Number,
},
methods: {
backTop() {
//无动画直接到达顶部
//this.$parent.$refs.scrollView.scrollTo(0, 0);
let that = this;
// 防止用户频繁点击返回顶部按钮,待返回顶部成功后设置scrollTrigger为初始值
if (that.scrollTrigger) {
return;
}
// 获取当前距离顶部的数值,设置每次上滑的高度直到滚动到顶部为止
let scrollTop = this.scrollTop;
let steep = scrollTop / 200;
let timer = setInterval(() => {
that.scrollTrigger = true;
// 上滑滚动的速度慢慢加快,第一次走200/1,然后减去已走的距离,下一次用剩下的距离再减去步进值,步进值也是不断变化,这样速度会越来越快
scrollTop -= steep;
// 步进值不改变的话会匀速缓慢上滑,不断增加步进值上滑的距离增加,视觉效果速度变快
steep += 5;
if (scrollTop <= 0) {
clearInterval(timer);
that.scrollTrigger = false;
}
//this.$parent.$refs.scrollView.scrollY(scrollTop); 不生效 不知道为啥 红红火火恍恍惚惚
this.$parent.$refs.scrollView.scrollTo(0, scrollTop);
}, 30);
},
},
};
</script>
<style lang="less">
img {
position: fixed;
right: 0;
bottom: 10%;
width: 0.64rem;
height: 0.64rem;
background: #f5f5f6;
z-index: 2; //设置层级在上层
}
</style>