mand-mobile 是滴滴团队的前端UI组件库, 本人自己基本是不使用的。这次主要想写的东西是关于mand-mobile
中的scrollView
,即上拉加载以及下拉刷新两个。是因为同事在用这套框架写这个需求时总是出现两个问题无法解决:
无法取消在下拉刷新后就会执行上拉加载问题
;当下拉刷新执行后,无法触发二次调用上拉加载
。
本文主要是围绕这两个问题编辑(文章结尾附带完整代码)。
mand-mobile 的使用
首先,我们先使用这套UI来还原问题出现的原因。
第一步:安装UI组件库;
npm install mand-mobile --save
# OR
yarn add mand-mobile
接下来就是在main.js
文件中引入mand-mobile
:
// 引入UI
import mandMobile from 'mand-mobile'
import 'mand-mobile/lib/mand-mobile.css'
import { ScrollView } from 'mand-mobile' // 这是滚动区域
// 使用UI
Vue.use(mandMobile)
Vue.component(ScrollView.name, ScrollView)
这里就是在组件中使用ScrollView
,实现上拉加载以及下拉刷新需求问题:
<!-- 滚动区域 -->
<md-scroll-view ref="scrollView"
:scrolling-x="false"
:is-prevent="true"
@scroll="$scroll"
@refreshing="$onRefresh"
@end-reached="$onEndReached">
<!-- 下拉刷新 -->
<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>
<!-- 页面主体-数据主页 -->
<ul class="mine">
<li class="items"
v-for="(item,index) in list"
:key="index">{{index+1}}</li>
<!-- 上拉加载的提示信息 -->
<li>
<md-scroll-view-more slot="more"
:is-finished="isFinished">
</md-scroll-view-more>
</li>
</ul>
</md-scroll-view>
// 引入
import { ScrollViewRefresh, ScrollView, ScrollViewMore } from 'mand-mobile'
// 使用
components: {
[ScrollViewRefresh.name]: ScrollViewRefresh,
[ScrollView.name]: ScrollView,
[ScrollViewMore.name]: ScrollViewMore
},
样式效果图如下:
结构写好了
功能需求
在methods
中添加代码,实现上拉刷新和下拉加载功能:
$onRefresh() {
setTimeout(() => {
console.log('刷新恢复最初页面信息')
this.list = 15 // 恢复初始数据
this.$refs.scrollView.finishRefresh()
this.isFinished = false // 可以重新加载
this.$refs.scrollView.finishLoadMore()
}, 2000)
},
$onEndReached() {
console.log('5555555555', this.nums)
if (this.isFinished) {
console.log('数据加载完了,不可再次执行3')
return
}
setTimeout(() => {
this.list += 10
if (this.list >= 40) {
// 数据加载完了,不可再次执行
this.isFinished = true
}
console.log('阶段加载结束2')
this.$refs.scrollView.finishLoadMore()
}, 1000)
}
加载前的样式:
加载后的效果:数据发生变动,证明上拉加载完成;
下拉刷新:
刷新结束后:数据恢复初始状态,上拉加载可再次执行;
出现的问题
问题1 - 无法取消在下拉刷新后就会执行上拉加载
按照mand-mobile
官网案例文档,我个人感觉如果上拉加载$onEndReached
和下拉刷新在同一个组件中使用,那么下拉刷新执行后就会默认触发上拉加载$onEndReached
。但是有时候我们在下拉刷新
的方法体中重置了初始化或者其他什么原因,导致我们不需要在刷新后还去触发加载更多。
官方是没有这个解决方法的,或者是我自己太菜了,没有找到。
我的解决办法是:使用一个变量来判断当前是刷新还是加载,如果是刷新,那么就通知$onEndReached
不要执行;反之,就让$onEndReached
执行加载。
那么,用什么变量来做判断条件呢?
后面看了官方文档,发现有个@scroll
属性,它可以获取到当前页面滚动距离顶部的距离,并且有个最恒定的情况:刷新时,top值小于等于零;加载时,top大于等于零。
具体的实际代码:
在局域外定义判断数组
let scrollTopArr= []
methods
滚动方法中写好处理逻辑:
$scroll({ scrollTop }) {
scrollTopArr.push(scrollTop) // 获取滚动数据
for (let i = 0; i < scrollTopArr.length; i++) {
if (scrollTopArr[i] == 0) scrollTopArr.splice(i, 1) // 删除刷新与加载都有的数 0
if (scrollTopArr[i] > 0) this.nums = true // 可以重新加载
if (scrollTopArr[i] < 0) this.nums = false // 不可以重新加载
}
scrollTopArr= []
},
在上拉加载中进行函数判断:
$onEndReached() {
console.log('5555555555', this.nums)
if (this.isFinished) {
console.log('数据加载完了,不可再次执行3')
return
}
// 如果是刷新时触发的,就不可以执行加载
if (this.nums) {
console.log('正在进行')
setTimeout(() => {
this.list += 10
if (this.list >= 40) {
// 数据加载完了,不可再次执行
this.isFinished = true
}
console.log('阶段加载结束2')
this.$refs.scrollView.finishLoadMore()
}, 1000)
} else {
console.log('未执行')
}
}
问题2 - 当下拉刷新执行后,无法触发二次调用上拉加载
将下面这两句代码:
this.isFinished = false; // 可以重新加载
this.$refs.scrollView.finishLoadMore();
放在刷新 方法/接口 中的then
里,如下:
// 假设
$onRefresh() {
getApi().then( () => {
this.isFinished = false // 可以重新加载
this.$refs.scrollView.finishLoadMore() // 通知加载结束
})
}
问题3 - ScrollView初始化成功后,不会自动触发上拉加载
在md-scroll-view
加上:immediate-check-end-reaching
附件 - 代码
template 部分:
<template>
<md-scroll-view ref="scrollView"
:scrolling-x="false"
:is-prevent="true"
@scroll="$scroll"
@refreshing="$onRefresh"
@end-reached="$onEndReached">
<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>
<ul class="mine">
<li class="items"
v-for="(item,index) in list"
:key="index">{{index+1}}</li>
<li>
<md-scroll-view-more slot="more"
:is-finished="isFinished">
</md-scroll-view-more>
</li>
</ul>
</md-scroll-view>
</template>
JavaScript :
<script>
import { ScrollViewRefresh, ScrollView, ScrollViewMore } from 'mand-mobile'
let scrollTopArr = []
export default {
components: {
[ScrollViewRefresh.name]: ScrollViewRefresh,
[ScrollView.name]: ScrollView,
[ScrollViewMore.name]: ScrollViewMore
},
data() {
return {
list: 15,
isFinished: false,
nums: true
}
},
mounted() {
window.ScrollViewTrigger1 = () => {
this.$refs.scrollView.triggerRefresh()
}
},
methods: {
$scroll({ scrollTop }) {
scrollTopArr.push(scrollTop)
for (let i = 0; i < scrollTopArr.length; i++) {
if (scrollTopArr[i] == 0) scrollTopArr.splice(i, 1)
if (scrollTopArr[i] > 0) this.nums = true // 可以重新加载
if (scrollTopArr[i] < 0) this.nums = false // 不可以重新加载
}
scrollTopArr = []
},
$onRefresh() {
setTimeout(() => {
console.log('刷新恢复最初页面信息')
this.list = 15 // 恢复初始数据
this.$refs.scrollView.finishRefresh()
this.isFinished = false // 可以重新加载
this.$refs.scrollView.finishLoadMore()
}, 2000)
},
$onEndReached() {
console.log('5555555555', this.nums)
if (this.isFinished) {
console.log('数据加载完了,不可再次执行3')
return
}
if (this.nums) {
console.log('正在进行')
setTimeout(() => {
this.list += 10
if (this.list >= 40) {
// 数据加载完了,不可再次执行
this.isFinished = true
}
console.log('阶段加载结束2')
this.$refs.scrollView.finishLoadMore()
}, 1000)
} else {
console.log('未执行')
}
}
}
}
</script>
css部分:
<style>
.mine {
width: 100%;
height: 527px;
padding-bottom: 40px;
overflow: hidden;
overflow-y: auto;
background: #ff11f2;
}
.items {
width: 80%;
height: 40px;
margin: auto;
margin-top: 2px;
background: #999999;
}
</style>