目录
背景 :
移动端项目 开发时,有数据长列表展示的场景需求,此时就用到了
Vant2 组件库里面的 <van-list> 列表组件,开始单独使用的时候还没有
下拉加载数据时滚动条会莫名自动返回到顶部的问题,后来为了提升用户的体验,
后续开发就结合加上了 Toast 轻提示 组件,然后当时也并没有发现这个问题,
直到后续项目开发的差不多了,反复测试的过程中偶尔感受到了这里怎么这么奇怪,
为何下拉至底部加载新一页的数据时,滚动条又回到了顶部呢?开始并没有很在意,
以为本来就这样的,但经过百度一番后,才发现原来此处算是一个小 bug ,
而且现在回想感觉确实很影响用户体验了,所以接下来分享一下解决方案 :
可以看到,往下滚动加载第二页数据的时候,滚动条会滚动到顶部。正常应该是滚动条位置不变
List 列表
瀑布流滚动加载,用于展示长列表,当列表即将滚动到底部时,
会触发事件并加载更多列表项。
Toast 轻提示
在页面中间弹出黑色半透明提示,用于消息通知、加载提示、操作结果提示等场景。
解决方案
1、不使用 Toast 的 加载提示
1-1、如果使用 异步加载数据 并使用了 Vant 中的 Toast 做加载中提示,
则有可能会导致列表滚动高度为 0 ,也就是回到了顶部。
只要在 list 加载回调里不使用 Toast 就可以避免这个问题。
1-2、因为每次 网络请求,使用了 Vant 的 Toast.loading 的加载中效果的 api,
如果去掉 Toast.loading 请求,则问题不会出现。
2、修改调整 pointer-event 属性值
主要原因是 Toast 组件在全局添加了 pointer-event: none
解决办法,在对应的 van-list 的属性值添加 pointer-event( 未实际实验过此方法,所以不确保准确性,小伙伴们可自行判断使用 )
3、判断是否为第一次加载再使用
因为还想保留着初次进入列表页面时的 Toast 的 加载提示,
所以这里我们判断一下,是否为第一页(初次进入页面),
是的话则使用 Toast 的 加载提示。
项目实际使用 :
<template> <div> <van-list v-if="dataList.length > 0" v-model="loading" :finished="finished" finished-text="没有更多了" @load="onLoad" > <p>{{ 'ItemName' }}</p> <van-cell v-for="item in dataList" :key="item" :title="item" /> </van-list> <div v-if="dataList.length === 0"> <img src="" alt="空" /> <p>暂无数据</p> </div> </div> </template> <script> import { getStData } from '@api/index'; export default { data() { return { dataList: [], // 列表数据 loading: false, // 加载显示与否 finished: false, // 是否加载完毕 formData: { surverId: '', currentPage: 1, // 当前页数 }, }; }, computed: { rqObj() { return this.$route.query || {}; }, }, created() { if (this.rqObj.id && this.rqObj.id !== null) { this.formData.surveyId = this.rqObj.id; this.getDataList(this.formData); } }, methods: { onLoad() { // 滚动到底部时触发 this.formData.currentPage++; this.getDataList(this.formData); }, async getDataList(data) { // 异步加载并使用Toast会导致列表滚动高度归零返回顶部 // Toast.loading({ // message: '加载中...', // forbidClick: true, // duration: 0, // 持续展示 toast // }); // 解决办法3:首次加载时使用提示,后续不再Toast提示 if (this.formData.currentPage === 1) { Toast.loading({ message: '加载中...', forbidClick: true, duration: 0, // 持续展示 toast }); } // ========================================== let res = await getStData(data); const { code, result } = res; if (code === '0') { if (result.lists && result.lists.length > 0) { this.dataList = this.dataList.concat(result.lists); } // 加载状态结束 this.loading = false; // 加载完成后需要将loading设置为false,以便下次触发加载 Toast.clear() } else { // 没有更多数据了(需停止继续加载) this.loading = false; this.finished = true; // 数据全部加载完成(true) } }, }, }; </script>
时隔多日,开发移动端项目时,此问题再次引发,需要进一步深入排查解除一下,
1、经排查发现 Toast.loading({ forbidClick: true }) 可以禁用背景点击,
但同样会导致 van-list 组件滚动高度出现问题
2、得出结论:由于 全局拦截器 加载中 Toast.loading({ forbidClick: true }) 导致
forbidClick 是否禁止背景点击 boolean false
4、forbidClick 设置为 false
Toast.loading({ forbidClick: false }) 将 forbidClick 设置为 false 可解决该问题,
但同样会导致背景可点击。
5、自定义组件
模拟 Toast 组件效果即可
<template>
<van-popup v-model="appLoading" :close-on-click-overlay="false" :overlay="false">
<div class="loading-wrap">
<van-loading color="#fff" />
</div>
</van-popup>
</template>
<script>
import { Popup, Loading } from 'vant'
export default {
components: {
[Popup.name]: Popup,
[Loading.name]: Loading
},
props: {
appLoading: {
type: Boolean,
default: false
}
}
}
</script>
<style lang="scss" scoped>
.van-popup {
background-color: transparent;
border-radius: 12px;
overflow: hidden;
}
.loading-wrap {
display: flex;
justify-content: center;
align-items: center;
width: 130px;
height: 130px;
background-color: rgba(0, 0, 0, 0.7);
}
</style>