uniapp:在子组件中实现下拉加载(onReachBottom)和上拉刷新(onPullDownRefresh)

本文介绍了在uniapp中,当页面结构相似且数据不同的情况下,如何通过抽取公共组件并利用uni.$emit()、uni.$on()和uni.$off()在子组件中实现下拉加载和上拉刷新功能,包括父页面设置监听事件以及子组件在挂载和卸载时的事件管理。

多个页面的页面结构完全相同,仅仅背景图和获取的列表数据不同,因此抽出一个公共组件,该组件占据整个父页面,根据父页面传入不同的参数向接口请求不同的列表数据。

现在想实现页面的下拉加载和上拉刷新功能,因为数据在子组件中请求,所以必须在子组件中实现上拉加载和下拉刷新,而onReachBottom和onPullDownRefresh又是页面内的处理函数,无法直接应用于组件中。

本篇文章借助uni.$emit()、uni.$on()和uni.$off()实现uniapp在子组件中下拉加载(onReachBottom)和上拉刷新(onPullDownRefresh)。


首先在pages.json中引入相关配置

// pages.json
{
  "path": "pages/resInfo/resPage", // 页面文件路径
  style": {
    "navigationBarTitleText": "我是页面标题"
    "enablePullDownRefresh": true, // 开启该页面下拉刷新,默认false
    "onReachBottomDistance": 100 // onReachBottom事件触发时距页面底部距离,默认50,单位px
  }
},
父页面:设置监听事件,onReachBottom和onPullDownRefresh与methods同级
// 父页面  
onReachBottom() {
  uni.$emit('onReachBottom') // 设置监听事件
},
onPullDownRefresh() {
  uni.$emit('onPullDownRefresh') // 设置监听事件
}
子组件:页面挂载前开始监听,离开页面时销毁监听,在uni.$on()的回调函数中进行上拉加载和下拉刷新操作,同样与methods同级
// 子组件
beforeMount() {
  uni.$on('onReachBottom', () => { // 监听上拉加载
    console.log("到达底部,onReachBottom")
  })
  uni.$on('onPullDownRefresh', () => { // 监听下拉刷新
    console.log("进行了上拉刷新,onPullDownRefresh")
  })
},
destroyed() {
  uni.$off('onReachBottom') // 销毁onReachBottom监听
  uni.$off('onPullDownRefresh') // 销毁onPullDownRefresh
}

  附上uniapp官网链接:uniapp官方文档onReachBottom介绍 | onPullDownRefresh | uni.$emit()、uni.$on()、uni.$off()

### 不依赖 `onPullDownRefresh` `onReachBottom` 的上拉加载下拉刷新分页功能实现UniApp 中,虽然 `onPullDownRefresh` `onReachBottom` 是常用的内置事件用于实现下拉刷新上拉加载功能,但如果不想使用这些方法,也可以通过监听滚动位置或其他方式手动触发相应的逻辑。以下是具体的实现方案。 --- #### 1. 下拉刷新替代方案 可以通过监听页面的触摸事件(如 `touchstart` `touchend`)或者绑定自定义手势来模拟下拉刷新的效果。以下是一个基于触摸事件的手动下拉刷新示例: ```html <template> <scroll-view class="container" scroll-y @touchstart="handleTouchStart" @touchmove="handleTouchMove" @touchend="handleTouchEnd"> <view v-for="(item, index) in listData" :key="index">{{ item.name }}</view> <view v-if="isRefreshing">正在刷新...</view> </scroll-view> </template> <script setup> import { ref } from 'vue'; const startY = ref(0); // 记录起始触摸点 const moveY = ref(0); // 记录移动中的触摸点 const isRefreshing = ref(false); // 刷新状态 const listData = ref([{ name: '初始数据项' }]); // 模拟获取数据的方法 function fetchData() { return new Promise((resolve) => { setTimeout(() => { resolve([{ name: '新数据项1' }, { name: '新数据项2' }]); }, 1000); }); } // 触摸开始时记录起点坐标 function handleTouchStart(event) { startY.value = event.touches[0].pageY; } // 触摸移动时计算偏移量 function handleTouchMove(event) { if (!isRefreshing.value && event.touches[0].pageY > startY.value + 50) { isRefreshing.value = true; // 达到一定距离后进入刷新状态 } } // 触摸结束时判断是否需要刷新 async function handleTouchEnd() { if (isRefreshing.value) { const newData = await fetchData(); listData.value = newData.concat(listData.value); // 将新数据拼接到前面 isRefreshing.value = false; // 结束刷新状态 } } </script> <style scoped> .container { height: 100vh; } </style> ``` --- #### 2. 上拉加载更多替代方案 可以通过监听 `scroll-view` 的滚动位置来检测何时接近页面底部并触发加载更多逻辑。具体实现如下: ```html <template> <scroll-view class="container" scroll-y @scroll="handleScroll" :style="{ height: windowHeight + 'px' }"> <view v-for="(item, index) in listData" :key="index">{{ item.name }}</view> <view v-if="isLoadingMore">正在加载更多...</view> </scroll-view> </template> <script setup> import { ref, onMounted } from 'vue'; import { getWindowHeight } from './utils'; // 自定义工具函数获取窗口高度 const listData = ref([]); const isLoadingMore = ref(false); // 加载更多状态 const hasMore = ref(true); // 是否有更多数据 const page = ref(1); // 当前页码 const pageSize = ref(10); // 每页大小 const scrollTop = ref(0); // 滚动条顶部位置 const scrollHeight = ref(0); // 可滚动区域总高度 const windowHeight = ref(getWindowHeight()); // 窗口可见区域高度 // 模拟获取数据的方法 function fetchMoreData(currentPage) { return new Promise((resolve) => { setTimeout(() => { const data = Array.from({ length: pageSize.value }).map((_, i) => ({ id: currentPage * pageSize.value + i, name: `Item ${currentPage * pageSize.value + i}`, })); resolve(data.length === 0 ? [] : data); }, 1000); }); } // 处理滚动事件 async function handleScroll(e) { scrollTop.value = e.detail.scrollTop; scrollHeight.value = e.detail.scrollHeight; if ( !isLoadingMore.value && hasMore.value && scrollTop.value + windowHeight.value >= scrollHeight.value - 50 ) { isLoadingMore.value = true; page.value += 1; const newData = await fetchMoreData(page.value); if (newData.length === 0) { hasMore.value = false; // 没有更多的数据了 } else { listData.value.push(...newData); // 追加新数据 } isLoadingMore.value = false; } } onMounted(async () => { const initialData = await fetchMoreData(page.value); listData.value = initialData; }); </script> <style scoped> .container { overflow-y: auto; } </style> ``` --- #### 3. 分页加载核心逻辑 无论采用何种方式触发加载更多操作,分页的核心逻辑都是一致的: - 维护当前页码 (`page`) 每页大小 (`pageSize`)- 在每次请求完成后更新数据列表,并检查是否有更多数据可加载[^1]。 --- ### 总结 以上两种方式分别实现了不依赖 `onPullDownRefresh` `onReachBottom` 的下拉刷新与上拉加载功能。通过监听触摸事件或滚动事件,可以灵活地控制刷新加载的行为。 --- ###
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值