前言
在使用uniapp开发项目的过程中,在很多场景里都需要下拉刷新和上拉加载,而 mescroll.js
则是一个非常精致的下拉刷新和上拉加载 js 框架。
官网地址:mescroll
介绍
mescroll.js
是在 H5端 运行的下拉刷新和上拉加载插件,时代变化太快, 作者已转向维护 mescroll 的 uni 版本了
-
mescroll的uni版本, 是专门用在uni-app的下拉刷新和上拉加载的组件, 支持一套代码编译到iOS、Android、H5、小程序等多个平台
-
mescroll的uni版本, 继承了mescroll.js的实用功能: 自动处理分页, 自动控制无数据, 空布局提示, 回到顶部按钮 …
-
mescroll的uni版本, 丰富的案例, 自由灵活的api, 超详细的注释, 可让您快速自定义真正属于自己的下拉上拉组件
-
mescroll的uni版本, 提供和两个组件, 其中支持配置成系统自带的下拉组件
-
是1.2.1版本新增的组件, 用来填补的不足 :
对比项 | mescroll-uni | mescroll-body | 系统自带的下拉组件 |
---|---|---|---|
本质 | scroll-view的滚动 | 原生页的滚动 | 原生页的滚动 |
是否支持自定义UI | 是 | 是 | x |
是否支持上拉翻页加载 | 是 | 是 | x |
支持配置空布局,回到顶部按钮 | 是 | 是 | x |
支持动态开启/禁止下拉功能 | 是 | 是 | 仅APP端可以 |
支持设置下拉区域出现的位置 | 是 | 是 | 仅APP端可以 |
支持局部区域滚动 (如嵌在弹窗,浮层中) | 是 | x | x |
数据不满屏,仍可上拉翻页加载 | 是 | x | x |
不必固定高度 | x | 是 | 是 |
不必配置pages.json | x | 是 | x |
可写入 原生组件, 如video,map,canvas | x | 是 | 是 |
支持titleNView的transparent透明渐变 | x | 是 | 是 |
超长的复杂的列表是否卡顿 (性能) | 低端机型会卡顿 | 流畅 | 流畅 |
总结 | 从1.2.1版本开始 绝大部分情况应优先考虑使用 mescroll-body 因为支持原生组件,且性能好 只有当需要局部区域滚动 (如嵌在弹窗,浮层,swiper中), 才考虑 mescroll-uni |
使用
- 插件市场, 点击右侧的"使用HBuilderX导入插件"按钮
- 下载示例, 找到合适的示例, 搬运代码(砖头), 比看文档快多啦
mescroll-body :
- 无需配置pages.json (检查是否配置了多余的属性):
{"path" : "pages/xxx/xxx", // 在具体的页面中, mescroll-body 无需像 mescroll-uni 那样需要配置 pages.json"style" : {"navigationBarTitleText" : "xxx","backgroundColorTop":"#FFFFFF", // iOS下拉bounce回弹区域的颜色 (与down.bgColor同步)"backgroundColorBottom":"#FFFFFF", // iOS上拉bounce回弹区域的颜色 (与up.bgColor同步)"disableScroll": false, //删除此项: mescroll-body必须允许原生页面滚动, 默认false"enablePullDownRefresh" : false, //删除此项: 不开启系统自带的下拉刷新, 默认false"app-plus" : {"bounce" : "none" //可选: 是否禁止iOS回弹和Android触顶触底的弧形阴影, 默认允许 (可配在 'globalStyle')},"mp-alipay":{"allowsBounceVertical":"NO"} //可选: 取消支付宝和钉钉小程序的iOS回弹 (可配在 'globalStyle')}},"globalStyle" : {"backgroundColorTop":"#FFFFFF" // iOS APP真机bounce回弹区域默认灰色,建议统一重置为白色}
- 在具体页面中的示例 (vue2) :
<template><view><mescroll-body @init="mescrollInit" @down="downCallback" @up="upCallback" :down="downOption" :up="upOption">// @init="mescrollInit" @down="downCallback" @up="upCallback"为固定值,不可删改(与mescroll-mixins保持一致) // :down="downOption" :up="upOption" 绝大部分情况无需配置 // :top="顶部偏移量" :bottom="底部偏移量" :topbar="状态栏" :safearea="安全区" (常用)// 此处支持写入原生组件 <view v-for="data in dataList"> 数据列表... </view></mescroll-body><view>fixed元素需写在mescroll-body的外面,否则下拉刷新时会降级为absolute <view></view></template><script>// 引入mescroll-mixins.jsimport MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js";import MescrollMixin from "@/components/mescroll-uni/mescroll-mixins.js"; // 非uni_modules版本import MescrollBody from "@/components/mescroll-uni/mescroll-body.vue"; // 非uni_modules版本export default {mixins: [MescrollMixin], // 使用mixincomponents: {MescrollBody},data() {return {mescroll: null, // mescroll实例对象 (此行可删,mixins已默认)// 下拉刷新的配置(可选, 绝大部分情况无需配置)downOption: { ...},// 上拉加载的配置(可选, 绝大部分情况无需配置)upOption: {page: {size: 10 // 每页数据的数量,默认10},noMoreSize: 5, // 配置列表的总数量要大于等于5条才显示'-- END --'的提示empty: {tip: '暂无相关数据'}},// 列表数据dataList: []}},methods: {/*mescroll组件初始化的回调,可获取到mescroll对象 (此处可删,mixins已默认)*/mescrollInit(mescroll) {this.mescroll = mescroll;},/*下拉刷新的回调, 重置列表为第一页 (此处可删,mixins已默认)downCallback(){this.mescroll.resetUpScroll();},/*上拉加载的回调*/upCallback(page) {// 此处可以继续请求其他接口// if(page.num == 1){// // 请求其他接口...// }// 如果希望先请求其他接口,再触发upCallback,可参考以下写法// if(!this.isInitxx){// apiGetxx().then(res=>{// this.isInitxx = true// this.mescroll.resetUpScroll() // 重新触发upCallback// }).catch(()=>{// this.mescroll.endErr()// })// return // 此处return,先获取xx// }let pageNum = page.num; // 页码, 默认从1开始let pageSize = page.size; // 页长, 默认每页10条uni.request({url: 'xxxx?pageNum='+pageNum+'&pageSize='+pageSize,success: (data) => {// 接口返回的当前页数据列表 (数组)let curPageData = data.xxx; // 接口返回的当前页数据长度 (如列表有26个数据,当前页返回8个,则curPageLen=8)let curPageLen = curPageData.length; // 接口返回的总页数 (如列表有26个数据,每页10条,共3页; 则totalPage=3)let totalPage = data.xxx; // 接口返回的总数据量(如列表有26个数据,每页10条,共3页; 则totalSize=26)let totalSize = data.xxx; // 接口返回的是否有下一页 (true/false)let hasNext = data.xxx; //设置列表数据if(page.num == 1) this.dataList = []; //如果是第一页需手动置空列表this.dataList = this.dataList.concat(curPageData); //追加新数据// 请求成功,隐藏加载状态//方法一(推荐): 后台接口有返回列表的总页数 totalPagethis.mescroll.endByPage(curPageLen, totalPage); //方法二(推荐): 后台接口有返回列表的总数据量 totalSize//this.mescroll.endBySize(curPageLen, totalSize); //方法三(推荐): 您有其他方式知道是否有下一页 hasNext//this.mescroll.endSuccess(curPageLen, hasNext); //方法四 (不推荐),会存在一个小问题:比如列表共有20条数据,每页加载10条,共2页.//如果只根据当前页的数据个数判断,则需翻到第三页才会知道无更多数据//如果传了hasNext,则翻到第二页即可显示无更多数据.//this.mescroll.endSuccess(curPageLen);// 如果数据较复杂,可等到渲染完成之后再隐藏下拉加载状态: 如// 建议使用setTimeout,因为this.$nextTick某些情况某些机型不触发setTimeout(()=>{this.mescroll.endSuccess(curPageLen)},20)// 上拉加载的 curPageLen 必传, 否则会一直显示'加载中...':1. 使配置的noMoreSize 和 empty生效2. 判断是否有下一页的首要依据: 当传的值小于page.size时(说明不满页了),则一定会认为无更多数据;比传入的totalPage, totalSize, hasNext具有更高的判断优先级;3. 当传的值等于page.size时(满页),才取totalPage, totalSize, hasNext判断是否有下一页传totalPage, totalSize, hasNext目的是避免方法四描述的小问题// 提示: 您无需额外维护页码和判断显示空布局,mescroll已自动处理好.// 当您发现结果和预期不一样时, 建议再认真检查以上参数是否传正确},fail: () => {// 请求失败,隐藏加载状态this.mescroll.endErr()}})},/*若希望重新加载列表,只需调用此方法即可(内部会自动page.num=1,再主动触发up.callback)*/reloadList(){this.mescroll.resetUpScroll();}}}</script>
- 在具体页面中的示例 (vue3) :
<template><mescroll-body @init="mescrollInit" @down="downCallback" @up="upCallback">// mescroll的极简示例,大部分情况就是这么用</mescroll-body>
</template><script setup>import { ref } from 'vue';import { onPageScroll, onReachBottom } from '@dcloudio/uni-app';import useMescroll from "@/uni_modules/mescroll-uni/hooks/useMescroll.js";import {apiGoods} from "@/api/mock.js"// 数据列表const goods = ref([]) // 调用mescroll的hook (注: mescroll-uni不用传onPageScroll,onReachBottom, 而mescroll-body必传)const { mescrollInit, downCallback } = useMescroll(onPageScroll, onReachBottom) // 上拉加载的回调: 其中num:当前页 从1开始, size:每页数据条数,默认10const upCallback = (mescroll)=>{apiGoods(mescroll.num, mescroll.size).then(res=>{const curPageData = res.list || [] // 当前页数据if(mescroll.num == 1) goods.value = []; // 第一页需手动制空列表goods.value = goods.value.concat(curPageData); //追加新数据//联网成功的回调,隐藏下拉刷新和上拉加载的状态;//mescroll会根据传的参数,自动判断列表如果无任何数据,则提示空;列表无下一页数据,则提示无更多数据;//方法一(推荐): 后台接口有返回列表的总页数 totalPage//mescroll.endByPage(curPageData.length, totalPage); //必传参数(当前页的数据个数, 总页数)//方法二(推荐): 后台接口有返回列表的总数据量 totalSize//mescroll.endBySize(curPageData.length, totalSize); //必传参数(当前页的数据个数, 总数据量)//方法三(推荐): 您有其他方式知道是否有下一页 hasNext//mescroll.endSuccess(curPageData.length, hasNext); //必传参数(当前页的数据个数, 是否有下一页true/false)//方法四 (不推荐),会存在一个小问题:比如列表共有20条数据,每页加载10条,共2页.如果只根据当前页的数据个数判断,则需翻到第三页才会知道无更多数据.mescroll.endSuccess(curPageData.length); // 请求成功, 结束加载}).catch(()=>{mescroll.endErr(); // 请求失败, 结束加载})}
</script>
mescroll-uni :
- 需要配置 pages.json :
{"path" : "pages/xxx/xxx", // 在具体的页面中, mescroll-uni 需要配置 pages.json, 而mescroll-body不需要"style" : {"navigationBarTitleText" : "xxx","enablePullDownRefresh" : false, // 删除此项: 不开启系统自带的下拉刷新, 默认false"disableScroll": false, // 删除此项, 否则页面无法滚动"app-plus" : {"bounce" : "none" // 取消APP端iOS回弹,避免与下拉刷新冲突 (可统一配在 'globalStyle')},"mp-alipay":{"allowsBounceVertical":"NO"} // 取消支付宝和钉钉小程序的iOS回弹,避免与下拉刷新冲突 (可统一配在 'globalStyle')}
}
- 在具体页面中的示例 :
<template>
<view><mescroll-uni @init="mescrollInit" @down="downCallback" @up="upCallback" :down="downOption" :up="upOption" >// 此处除了不能写原生组件,其他的与 mescroll-body 的一致 > </mescroll-uni><view>原生组件和fixed元素需写在mescroll-uni的外面,否则滚动列表时会抖动 <view>
<view>
</template><script>// 与 mescroll-body 的一致 >
</script>
效果图(loading样式可以自定义)
上拉效果
下拉效果
参数配置
mescroll
的配置可以使得页面样式变得多样化,更多配置可以去官网看一下。
downOption: {use: true, // 是否启用下拉刷新; 默认trueauto: true, // 是否在初始化完毕之后自动执行下拉刷新的回调; 默认truenative: false, // 是否使用系统自带的下拉刷新; 默认false; 仅mescroll-body生效 (值为true时,还需在pages配置enablePullDownRefresh:true;详请参考mescroll-native的案例)autoShowLoading: false, // 如果设置auto=true(在初始化完毕之后自动执行下拉刷新的回调),那么是否显示下拉刷新的进度; 默认falseisLock: false, // 是否锁定下拉刷新,默认false;offset: 60, // 在列表顶部,下拉大于80upx,松手即可触发下拉刷新的回调inOffsetRate: 1, // 在列表顶部,下拉的距离小于offset时,改变下拉区域高度比例;值小于1且越接近0,高度变化越小,表现为越往下越难拉outOffsetRate: 0.2, // 在列表顶部,下拉的距离大于offset时,改变下拉区域高度比例;值小于1且越接近0,高度变化越小,表现为越往下越难拉bottomOffset: 20, // 当手指touchmove位置在距离body底部20upx范围内的时候结束上拉刷新,避免Webview嵌套导致touchend事件不执行minAngle: 45, // 向下滑动最少偏移的角度,取值区间 [0,90];默认45度,即向下滑动的角度大于45度则触发下拉;而小于45度,将不触发下拉,避免与左右滑动的轮播等组件冲突;bgColor: "#E75A7C", // 背景颜色 (建议在pages.json中再设置一下backgroundColorTop)textColor: "#fff", // 文本颜色 (当bgColor配置了颜色,而textColor未配置时,则textColor会默认为白色)textInOffset: "下拉刷新", // 下拉的距离在offset范围内的提示文本textOutOffset: "释放更新", // 下拉的距离大于offset范围的提示文本textLoading: "蒋皓洁稍等加载中 ...", // 加载中的提示文本},upOption: {use: true, // 是否启用上拉加载; 默认trueauto: true, // 是否在初始化完毕之后自动执行上拉加载的回调; 默认trueisLock: false, // 是否锁定上拉加载,默认false;isBoth: true, // 上拉加载时,如果滑动到列表顶部是否可以同时触发下拉刷新;默认true,两者可同时触发;page: {num: 0, // 当前页码,默认0,回调之前会加1,即callback(page)会从1开始size: 10, // 每页数据的数量time: null, // 加载第一页数据服务器返回的时间; 防止用户翻页时,后台新增了数据从而导致下一页数据重复;},noMoreSize: 3, // 如果列表已无数据,可设置列表的总数量要大于等于5条才显示无更多数据;避免列表数据过少(比如只有一条数据),显示无更多数据会不好看offset: 80, // 距底部多远时,触发upCallback(仅mescroll-uni生效, 对于mescroll-body则需在pages.json设置"onReachBottomDistance")bgColor: "transparent", // 背景颜色 (建议在pages.json中再设置一下backgroundColorTop)textColor: "gray", // 文本颜色 (当bgColor配置了颜色,而textColor未配置时,则textColor会默认为白色)textLoading: "加载中 ...", // 加载中的提示文本textNoMore: "-- END --", // 没有更多数据的提示文本toTop: {// 回到顶部按钮,需配置src才显示src: "https://www.mescroll.com/img/mescroll-totop.png", // 图片路径offset: 1000, // 列表滚动多少距离才显示回到顶部按钮,默认1000duration: 300, // 回到顶部的动画时长,默认300ms (当值为0或300则使用系统自带回到顶部,更流畅; 其他值则通过step模拟,部分机型可能不够流畅,所以非特殊情况不建议修改此项)zIndex: 9990, // fixed定位z-index值left: null, // 到左边的距离, 默认null. 此项有值时,right不生效. (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx)right: 20, // 到右边的距离, 默认20 (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx)bottom: 120, // 到底部的距离, 默认120 (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx)safearea: false, // bottom的偏移量是否加上底部安全区的距离, 默认false, 需要适配iPhoneX时使用 (具体的界面如果不配置此项,则取mescroll组件props的safearea值)width: 72, // 回到顶部图标的宽度, 默认72 (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx)radius: "50%", // 圆角, 默认"50%" (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx)},empty: {use: true, // 是否显示空布局icon: "https://www.mescroll.com/img/mescroll-empty.png", // 图标路径tip: "~ 暂无相关数据 ~", // 提示btnText: "去逛逛 >", // 按钮fixed: false, // 是否使用fixed定位,默认false; 配置fixed为true,以下的top和zIndex才生效 (transform会使fixed失效,最终会降级为absolute)top: "100rpx", // fixed定位的top值 (完整的单位值,如 "10%"; "100rpx")zIndex: 99, // fixed定位z-index值},onScroll: true, // 是否监听滚动事件, 默认false, 仅mescroll-uni生效; mescroll-body直接声明onPageScroll (配置为true时,可@scroll="scroll"获取到滚动条位置和方向; 注意监听列表滚动是非常耗性能的,很容易出现卡顿,非特殊情况不要配置此项)},
小发现
- 官网为了适配苹果端,用了组件的情况下,最下面会有一个留白,大部分同学应该不需要处理,可是样式已经是做过适配的情况,又不需要此留白,可在全局加上如下样式:
.mescroll-bottombar{height: unset !important; }
- 使用组件的话最下面会有
--END--
这样的文字提示,但是如果后端返回的total,小于5条,或者页面数据总共小于5条,那么此文字是无效的,因此大家需要任何情况都需要文字,处理返回的条数传入组件大于5条即可
小结
- 本文大部分主要复制官网内容,做一个简单的梳理,更多精彩的内容,请移步 官网
- 官网还有
<mescroll-empty>
等使用方法 - 个性化使用组件,还可以有很多好看的动画以及配置