mescroll-uni 完全指南——Vue3 setup格式
目录
UniApp 下拉刷新与上拉加载神器 —— mescroll-uni 完全指南
一、mescroll-uni 是什么?
概念区别
二、组件的使用方法(详细介绍)
1. 基本用法
2. 常用 API
3. Hook 方式(推荐)
三、开发步骤(如何使用)
步骤 1:安装插件
步骤 2:在模板里加组件
步骤 3:在脚本里写逻辑
步骤 4:验证效果
四、常见坑
顶部 TabBar 固定
1. 为什么单靠 z-index 不行?
2. 固定的核心思路
UniApp 下拉刷新与上拉加载神器 —— mescroll-uni 完全指南
在移动端开发中,列表页几乎是必备场景:朋友圈、新闻流、商品列表……都会遇到 “下拉刷新” 和 “上拉加载更多”。
自己去写这些逻辑,要处理:
-
手势监听
-
loading 动画
-
分页参数
-
空数据 & 没有更多的提示
既繁琐又容易出 bug。
好在 mescroll-uni
已经帮我们封装好了一整套,只需要少量配置,就能实现完整的体验。
官网:mescroll -- 精致的下拉刷新和上拉加载js框架
一、mescroll-uni 是什么?
mescroll-uni
是基于 mescroll 的 UniApp 组件,核心功能包括:
-
下拉刷新:用户下拉时重新请求数据。
-
上拉加载:滚动到底部时自动请求下一页。
-
分页管理:自动维护
pageNum
和pageSize
。 -
空态/无更多提示:内置状态显示,不需要自己额外写。
一句话总结:你只需要写请求接口的逻辑,其他交给 mescroll。
概念区别
-
下拉刷新 (pull down refresh)
用户从页面顶部往下拉 → 一般语义是“我要最新数据”。
👉 在 mescroll 里:会调用downCallback
。
👉 常用写法:downCallback
里调用resetUpScroll()
,强制重新跑第一页。 -
上拉加载 (pull up load more)
用户滚动到底部 → 一般语义是“我要更多数据”。
👉 在 mescroll 里:会调用upCallback
,参数里带page.num
(第几页)。
👉 如果page.num=1
,就是第一页;如果是 2,就是第二页,以此类推。
二、组件的使用方法(详细介绍)
1. 基本用法
在页面里引入 <mescroll-body>
组件,把列表包裹在里面:
<mescroll-body:down="{ auto: true }":up="{ page: { num: 0, size: 10 } }"@init="mescrollInit"@down="downCallback"@up="upCallback"
><view v-for="item in list" :key="item.id">{{ item.title }}</view>
</mescroll-body>
-
:down="{ auto:true }"
→ 进入页面时自动触发下拉刷新。 -
:up="{ page:{ num:0, size:10 } }"
→ 从第 1 页开始分页,每页 10 条。 -
@init="mescrollInit"
→ 初始化时会传出实例对象。 -
@down="downCallback"
→ 下拉时触发,一般用于重置列表。 -
@up="upCallback"
→ 上拉或重置时触发,你的唯一数据请求入口。
2. 常用 API
mescroll 实例对象(通过 mescrollInit
拿到)常用方法有:
-
resetUpScroll()
👉 重置分页为第一页,并自动触发upCallback(num=1)
。
用于切换分类 / 搜索 / Tab 切换时。 -
endBySize(curPageSize, totalSize)
👉 请求成功后调用,告诉 mescroll 当前页数量和总条数。 -
endErr()
👉 请求失败时调用,结束 loading 避免一直转圈。
3. Hook 方式(推荐)
官方提供了 Hook,可以直接解构出常用方法:
import useMescroll from '@/uni_modules/mescroll-uni/hooks/useMescroll.js'
import { onPageScroll, onReachBottom } from '@dcloudio/uni-app'const { mescrollInit, downCallback, getMescroll } =useMescroll(onPageScroll, onReachBottom)
-
mescrollInit
:绑定到模板的@init
。 -
downCallback
:绑定到@down
,内部会自动调用resetUpScroll()
。 -
getMescroll()
:获取当前实例(推荐用这个,而不是mescrollRef.value
,因为版本差异可能导致mescrollRef
没有定义)。
三、开发步骤(如何使用)
下面分步骤教你把 mescroll-uni 跑起来。
步骤 1:安装插件
在 HBuilderX 插件市场导入 mescroll-uni
,项目里会出现 uni_modules/mescroll-uni
目录。
步骤 2:在模板里加组件
<mescroll-body:down="{ auto: true }":up="{auto: false,page: { num: 0, size: 10 },noMoreSize: 0,textNoMore: '—— 没有更多了 ——'}"@init="mescrollInit"@down="downCallback"@up="upCallback"
><view v-for="item in list" :key="item.id">{{ item.title }}</view>
</mescroll-body>
步骤 3:在脚本里写逻辑
import { ref } from 'vue'
import { onPageScroll, onReachBottom } from '@dcloudio/uni-app'
import useMescroll from '@/uni_modules/mescroll-uni/hooks/useMescroll.js'
import request from '@/utils/request'const list = ref([])// 取 Hook 提供的方法
const { mescrollInit, downCallback, getMescroll } =useMescroll(onPageScroll, onReachBottom)// 唯一的数据请求函数
const upCallback = async (m) => {const { num: pageNum, size: pageSize } = mtry {const res = await request.get('/api/list', { params: { pageNum, pageSize } })const rows = res.data.rows || []const total = res.data.total || 0if (pageNum === 1) list.value = [] // 首次清空list.value = list.value.concat(rows)m.endBySize(rows.length, total) // 通知 mescroll} catch (e) {m.endErr()}
}// 切换 Tab 时调用
function switchTab() {list.value = []// 重置列表数据getMescroll().resetUpScroll()
}
步骤 4:验证效果
-
页面加载时 → 自动触发下拉 →
resetUpScroll()
→upCallback(pageNum=1)
请求数据。 -
向下滚动到底部 → 自动触发
upCallback(pageNum=2)
请求下一页。 -
切换 Tab →
getMescroll().resetUpScroll()
→ 重新加载第一页。
四、常见坑
pageNum 从 2 开始
-
mescroll 内部的逻辑:
page:{ num:0, size:10 }
→ 调用resetUpScroll()
时会自动 +1,所以第一次触发upCallback
的page.num
就是 1。 -
但如果你一开始把配置写成
page:{ num:1, size:10 }
,那第一次触发upCallback
就会变成 2,数据直接从第二页开始,请求错位。 -
解决:初始一定要写成 0:
首屏请求重复
-
你自己在
onMounted
里写了fetchList()
,同时:down="{ auto:true }"
又会自动触发一次下拉刷新。 -
结果首屏第一页被请求了两次。
-
解决:只保留
down.auto=true
,不要再手动请求。
搜索/切换 Tab 不刷新
-
改了关键字或分类,只更新了数据数组,却没重置分页。
-
解决:一定要在搜索 / 切换 Tab 后调用:
list.value = [] getMescroll().resetUpScroll()
顶部 TabBar 固定
在做资讯/公告类页面时,常常需要 搜索框 + TabBar 固定在顶部,下方内容可以自由滚动加载。如果只是给 TabBar 加上 z-index
,是无法固定的,因为它本身仍然在滚动容器里。
1. 为什么单靠 z-index 不行?
-
z-index
只决定层级,不能决定是否滚动。 -
在
mescroll-body
(内部基于scroll-view
)中,TabBar 会随内容一起滚动。 -
要固定,必须让 TabBar 脱离滚动容器,使用
position: fixed
或sticky
。
但是 sticky
在 scroll-view
里经常失效,所以最稳妥的方法就是 fixed。
2. 固定的核心思路
实现步骤主要有 4 步:
-
把头部(搜索 + Tabs)放到滚动容器外
.header-fixed {position: fixed;top: 0;left: 0;right: 0;z-index: 999;background: #f5f5f5; }
这样它不会随着列表滚动。
-
用占位元素把内容顶下去
<view :style="`height:${headerH}px`"></view>
避免列表被固定头部遮住。
-
动态计算头部高度
const headerH = ref(120) // 先给个保底值 onMounted(() => {nextTick(() => {const q = uni.createSelectorQuery()q.select('#fixed-header').boundingClientRect(rect => {if (rect) {console.log('fixed-header rect:', rect) // 打印完整 rect 对象console.log('header 高度:', rect.height) // 只看高度headerH.value = rect.height + 10 // 有间距}}).exec()}) })
-
告诉 mescroll 顶部被占了多少
<mescroll-body :top="headerH" ...> </mescroll-body>
mescroll 会把滚动区域下移,避免遮挡。