微信小程序uni-app+vue3实现局部上下拉刷新和scroll-view动态高度计算
微信小程序uni-app+vue3实现局部上下拉刷新和scroll-view动态高度计算
前言
在uni-app+vue3项目开发中,经常需要实现列表的局部上下拉刷新功能。由于网上相关教程较少且比较零散,本文将详细介绍如何使用scroll-view组件实现这一功能,包括动态高度计算、下拉刷新、上拉加载等完整实现。
重要提示
⚠️ triggered状态管理是关键
- triggered必须手动管理其true/false状态
- 不正确的状态管理会导致下拉刷新卡住
- 需要在适当的时机重置状态
核心实现思路
- 状态定义
// 下拉刷新相关状态
const triggered = ref(false) // 触发下拉刷新状态
const refresherEnabled = ref(true) // 是否启用下拉刷新
- 关键事件处理
// 下拉过程中触发
const onPulling = () => {triggered.value = true // 手动设置为true
}// 刷新结束时触发
const onRestore = () => {triggered.value = false // 手动重置为false
}// 刷新中断时触发
const onAbort = () => {triggered.value = false // 手动重置为false
}// 刷新数据处理
const refreshHistoryList = async () => {triggered.value = true // 开始刷新时设置为truetry {// 执行刷新逻辑await loadData()} catch (err) {console.error('刷新失败:', err)} finally {triggered.value = false // 完成后一定要设置为false}
}
- 组件配置
<scroll-view:refresher-enabled="refresherEnabled":refresher-triggered="triggered"@refresherrefresh="refreshHistoryList"@refresherpulling="onPulling"@refresherrestore="onRestore"@refresherabort="onAbort"
><!-- 列表内容 -->
</scroll-view>
注意事项
-
状态重置时机
- 刷新完成时必须重置
- 刷新中断时必须重置
- 组件卸载时最好重置
-
常见问题
- 忘记重置导致卡住
- 重置时机不对导致异常
- 多个事件重复设置状态
-
最佳实践
- 使用try/finally确保重置
- 统一状态管理位置
- 添加适当的错误处理
快速开始
1. 基础配置
2. 组件结构
在template中创建scroll-view组件:
<template><scroll-view :style="{ height: scrollViewHeight }":scroll-y="true":refresher-enabled="refresherEnabled"@refresherrefresh="refreshHistoryList"@refresherpulling="onPulling"@scroll="roll":enable-passive="true":show-scrollbar="false"@refresherrestore="onRestore"@refresherabort="onAbort":refresher-triggered="triggered"ref="scrollView"><!-- 列表内容 --><view class="empty-state" v-show="!list.length">暂无数据</view><view v-for="(item, index) in list" :key="index"><!-- 列表项内容 --></view><up-loadmore v-if="list.length>0" :status="scrollStatus" @loadmore="loadmore"/></scroll-view>
</template>
注意uwiewPlus组件库up-loadmore是通过@loadmore来触发@click的效果的。
3. 核心状态定义
| 属性/事件 | 类型 | 默认值 | 必填 | 说明 |
|---|---|---|---|---|
| style.height | string | - | 是 | 设置scroll-view高度,不设置无法滚动 |
| scroll-y | boolean | false | 否 | 是否允许纵向滚动 |
| scroll-x | boolean | false | 否 | 是否允许横向滚动 |
| refresher-enabled | boolean | false | 否 | 是否开启下拉刷新功能 |
| refresher-triggered | boolean | false | 否 | 当前下拉刷新状态 |
| enable-passive | boolean | false | 否 | 是否开启被动监听滚动事件 |
| show-scrollbar | boolean | true | 否 | 是否显示滚动条 |
| @refresherrefresh | function | - | 否 | 下拉刷新触发时的回调 |
| @refresherpulling | function | - | 否 | 下拉过程中触发的回调 |
| @refresherrestore | function | - | 否 | 下拉刷新复位时触发的回调 |
| @refresherabort | function | - | 否 | 下拉刷新被中止时触发的回调 |
| @scroll | function | - | 否 | 滚动时触发的回调函数 |
| ref | string | - | 否 | 组件的引用标识 |
// 下拉刷新相关
const triggered = ref(false) // 触发下拉刷新状态
const refresherEnabled = ref(true) // 是否启用下拉刷新
const currentScrollTop = ref(0) // 当前滚动位置
const scrollViewHeight = ref('400rpx') // scroll-view高度// 分页相关
const currentPage = ref(1) // 当前页码
const pageSize = ref(10) // 每页数量
const totalPage = ref(0) // 总页数
const scrollStatus = ref<string>('loadmore') // 滚动状态
4. 动态高度计算
onReady(() => {// 获取系统信息const systemInfo = uni.getSystemInfoSync()const windowHeight = systemInfo.windowHeight// 获取各元素高度const query = uni.createSelectorQuery()Promise.all([new Promise<number>(resolve => {query.select('.u-demo-block').boundingClientRect(data => {resolve(data?.height || 0)}).exec()}),// ... 获取其他元素高度]).then(([demoBlockHeight, titleHeight, uploadHeight]) => {// 计算scroll-view高度const scrollHeight = windowHeight - demoBlockHeight - titleHeight - uploadHeight - 40scrollViewHeight.value = `${scrollHeight}rpx`})
})
核心功能实现
1. 下拉刷新
// 下拉刷新处理
const refreshHistoryList = async () => {triggered.value = truecurrentPage.value = 1try {const res = await loadFirstPage()list.value = res.dataupdateLoadStatus()} catch (err) {console.error('刷新失败:', err)} finally {triggered.value = false}
}
2. 上拉加载
// 上拉加载更多
const loadmore = async () => {if (scrollStatus.value === 'noMore') returnscrollStatus.value = 'loading'try {const res = await loadMoreData(++currentPage.value)list.value.push(...res.data)updateLoadStatus()} catch (err) {console.error('加载失败:', err)scrollStatus.value = 'loadmore'}
}
3. 滚动事件处理
const roll = (e: any) => {currentScrollTop.value = e.detail.scrollTop// 控制下拉刷新启用状态refresherEnabled.value = e.detail.scrollTop < 50// 触底加载更多const scrollBottom = e.detail.scrollHeight - e.detail.scrollTop - e.detail.heightif (scrollBottom < 50 && scrollStatus.value === 'loadmore') {loadmore()}
}
注意事项
-
高度计算
- 需要考虑所有固定元素的高度
- 使用rpx单位确保跨设备兼容性
- 预留适当边距避免内容被遮挡
-
性能优化
- 使用enable-passive提升滚动性能
- 合理控制刷新频率
- 避免频繁触发加载更多
-
用户体验
- 添加加载提示
- 保持滚动位置
- 合理控制刷新触发时机
加载更多组件使用
⚠️ up-loadmore组件使用说明
- 基础配置
<up-loadmore v-if="list.length>0" :status="scrollStatus" @loadmore="loadmore"loadmore-text="加载更多"
/>
- 状态管理
// 加载状态
const scrollStatus = ref<string>('loadmore') // 可选值: loadmore/loading/noMore// 加载更多处理
const loadmore = async () => {if (scrollStatus.value === 'noMore') returnscrollStatus.value = 'loading' // 设置加载中状态try {const res = await loadMoreData(++currentPage.value)list.value.push(...res.data)// 更新加载状态if (currentPage.value >= totalPage.value) {scrollStatus.value = 'noMore'} else {scrollStatus.value = 'loadmore'}} catch (err) {console.error('加载失败:', err)scrollStatus.value = 'loadmore'}
}
- 触发方式
- 通过
@loadmore事件监听触发加载 - 可以在scroll-view滚动到底部时自动触发
- 也可以点击"加载更多"文本手动触发
- 状态说明
loadmore: 可以加载更多loading: 正在加载中noMore: 没有更多数据
完整示例
<scroll-view @scroll="roll":scroll-y="true"
><!-- 列表内容 --><view v-for="(item, index) in list" :key="index">{{ item }}</view><!-- 加载更多组件 --><up-loadmorev-if="list.length>0":status="scrollStatus"@loadmore="loadmore"loadmore-text="加载更多"/>
</scroll-view><script setup lang="ts">
const scrollStatus = ref('loadmore')
const currentPage = ref(1)
const list = ref([])// 滚动触底自动加载
const roll = (e: any) => {const scrollBottom = e.detail.scrollHeight - e.detail.scrollTop - e.detail.heightif (scrollBottom < 50 && scrollStatus.value === 'loadmore') {loadmore()}
}// 加载更多处理
const loadmore = async () => {if (scrollStatus.value === 'noMore') returnscrollStatus.value = 'loading'try {const res = await loadMoreData(currentPage.value++)list.value.push(...res.data)scrollStatus.value = res.hasMore ? 'loadmore' : 'noMore'} catch (err) {console.error('加载失败:', err)scrollStatus.value = 'loadmore'}
}
</script>
总结
通过本教程的学习,我们掌握了:
- scroll-view组件的基本使用
- 动态高度计算方法
- 下拉刷新实现
- 上拉加载更多功能
- 滚动位置维护
参考资料
- 微信小程序官方文档
- Vue3文档
admore’ : ‘noMore’
} catch (err) {
console.error(‘加载失败:’, err)
scrollStatus.value = ‘loadmore’
}
}
## 总结通过本教程的学习,我们掌握了:
1. scroll-view组件的基本使用
2. 动态高度计算方法
3. 下拉刷新实现
4. 上拉加载更多功能
5. 滚动位置维护## 参考资料
- [微信小程序官方文档](https://developers.weixin.qq.com/miniprogram/dev/component/scroll-view.html)
- [Vue3文档](https://v3.cn.vuejs.org/)
- [uview-plus文档](https://uiadmin.net/uview-plus/)
相关文章:
微信小程序uni-app+vue3实现局部上下拉刷新和scroll-view动态高度计算
微信小程序uni-appvue3实现局部上下拉刷新和scroll-view动态高度计算 前言 在uni-appvue3项目开发中,经常需要实现列表的局部上下拉刷新功能。由于网上相关教程较少且比较零散,本文将详细介绍如何使用scroll-view组件实现这一功能,包括动态高度计算、下拉刷新、上拉加载等完整…...
为什么类 UNIX 操作系统通常内置编译器?为什么 Windows 更倾向于直接使用二进制文件?
操作系统是否内置编译器,取决于该系统的设计目标、用户群体以及常见的使用场景。以下是内置编译器和直接使用二进制的设计理念和原因的分析: 为什么类 UNIX 操作系统通常内置编译器? 面向开发者的需求: 类 UNIX 系统(如…...
吉林大学23级数据结构上机实验(第7周)
A 去火车站 寒假到了,小明准备坐火车回老家,现在他从学校出发去火车站,CC市去火车站有两种方式:轻轨和公交车。小明为了省钱,准备主要以乘坐公交为主。CC市还有一项优惠政策,持学生证可以免费乘坐一站轻轨&…...
实验13 使用预训练resnet18实现CIFAR-10分类
1.数据预处理 首先利用函数transforms.Compose定义了一个预处理函数transform,里面定义了两种操作,一个是将图像转换为Tensor,一个是对图像进行标准化。然后利用函数torchvision.datasets.CIFAR10下载数据集,这个函数有四个常见的…...
【开发文档】资源汇总,持续更新中......
文章目录 AI大模型数据集PytorchPythonUltralyticsOpenCVNetronSklearnCMakeListsNVIDIADocker刷题网站持续更新,欢迎补充 本文汇总了一些常用的开发文档资源,涵盖了常用AI大模型、刷题网站、Python、Pytorch、OpenCV、TensorRT、Docker 等技术栈。通过这…...
【k8s实践】 创建第一个Pod(Nginx)
环境 Rocky Linux9.4 x86_64 VM安装了Microk8s (参考:Microk8s安装方法) 说明: 其他k8s(例如: k3s, kubernetes)创建Pod的方法和Microk8s没啥区别,可以参考本文 目标 创建一个Nginx的Pod,映射宿主机30000端口到Pod容器的80端口;客户端能通…...
盘古大模型实战
0 前言 前一段时间,在学习人工智能的同时,也去了解了一下几乎是作为人工智能在气象上应用的一大里程碑式的研究成果-华为盘古气象大模型。正是盘古大模型的出现,促使天气预报的未来发展方向多了个除天气学方法、统计学方法、数值预报方法之外…...
Python subprocess.run 使用注意事项,避免出现list index out of range
在执行iOS UI 自动化专项测试的时候,在运行第一遍的时候遇到了这样的错误: 2024-12-04 20:22:27 ERROR conftest pytest_runtest_makereport 106 Test test_open_stream.py::TestOpenStream::test_xxx_open_stream[iPhoneX-xxx-1-250] failed with err…...
包管理器npm,cnpm,yarn和pnpm
npm (Node Package Manager) 核心技术与工作原理 依赖解析: 广度优先搜索(BFS):npm 使用 BFS 算法来解析依赖树,尽量扁平化 node_modules 目录以减少重复的依赖项。冲突处理:如果两个包需要同一个依赖的不…...
树莓派4B使用opencv读取摄像头配置指南
本文自己记录,给我们lab自己使用,其他朋友们不一定完全适配,请酌情参考。 一. 安装opecnv 我们的树莓派4B默认是armv7l架构,安装的miniconda最新的版本 Miniconda3-latest-Linux-armv7l.sh 仍然是python3.4几乎无法使用ÿ…...
Spring Boot 进阶话题:部署
部署是将应用程序从开发环境移动到可以供用户访问的生产环境的过程。Spring Boot提供了多种部署选项,包括打包为可执行jar文件,使用Docker容器化,以及部署到云平台。 打包Spring Boot应用 Spring Boot应用可以打包为包含所有依赖、类和资源…...
Python 3 和 MongoDB 的集成使用
Python 3 和 MongoDB 的集成使用 MongoDB 是一个流行的 NoSQL 数据库,以其灵活的数据模型和强大的查询功能而闻名。Python 3 作为一种广泛使用的编程语言,与 MongoDB 的集成变得日益重要。本文将介绍如何在 Python 3 环境中集成和使用 MongoDBÿ…...
perl语言中模式匹配的左右关系
这里简单记录一下,在perl语言中,关于模式匹配的一个细节: 在进行模式匹配的时候,左边写需要查找的字符串,右侧写匹配的关键字. 两边的顺序不一样就会导致匹配结果不一样. 测试代码:…...
【漏洞复现】网动统一通信平台(ActiveUC)接口iactiveEnterMeeting存在信息泄露漏洞
🏘️个人主页: 点燃银河尽头的篝火(●’◡’●) 如果文章有帮到你的话记得点赞👍+收藏💗支持一下哦 @TOC 一、漏洞概述 1.1漏洞简介 漏洞名称:网动统一通信平台(ActiveUC)接口iactiveEnterMeeting存在信息泄露漏洞漏洞编号:无漏洞类型:信息泄露漏洞威胁等级:高危影…...
C++ STL 容器系列(三)list —— 编程世界的万能胶,数据结构中的百变精灵
STL系列学习参考: C STL系列__zwy的博客-CSDN博客https://blog.csdn.net/bite_zwy/category_12838593.html 学习C STL的三个境界,会用,明理,能扩展,STL中的所有容器都遵循这个规律,下面我们就按照这三个境…...
Java经典面试题总结(附答案)2025
点击获取PDF版 10、如何将字符串反转? 添加到StringBuilder中,然后调用reverse()。 11、String 类的常用方法都有那些? equals、length、contains、replace、split、hashcode、indexof、substring、trim、toUpperCase、toLowerCase、isEmpt…...
Stylus 浏览器扩展开发-Cursor AI辅助
项目起源 作为一个经常需要长时间盯着屏幕的开发者,我一直在寻找一个简单的方法来保护眼睛。最初的想法很简单:将网页背景色替换成护眼的豆沙绿。虽然市面上已经有类似的扩展,但我想要一个更加轻量且可定制的解决方案。 这个简单的需求逐渐…...
DAY35|动态规划Part03|LeetCode:01背包问题 二维、01背包问题 一维、416. 分割等和子集
目录 01背包理论基础(一) 基本思路 C代码 01背包理论基础(二) 基本思路 C代码 LeetCode:416. 分割等和子集 基本思路 C代码 01背包理论基础(一) 题目链接:卡码网46. 携带研究材料 文字…...
创建空向量:std::vector<int> v,刚创建时大小为0
创建一个空的std::vector<int> v会在刚创建时具有大小(size)为0的特点。这意味着此时向量中没有任何元素,而且其容量(capacity)也返回0,表明还没有为这个向量分配任何内存空间3。换句话说,…...
VBA基础2
VBA基础2 sub过程语法对单元格进行赋值操作连续赋值不连续赋值 cells (行,列)行引用rows列引用 (columns)offset位移属性End属性(指定返回) 使用VBA编辑器需要用AltF11打开 或者VB编辑器打开 可…...
大数据学习栈记——Neo4j的安装与使用
本文介绍图数据库Neofj的安装与使用,操作系统:Ubuntu24.04,Neofj版本:2025.04.0。 Apt安装 Neofj可以进行官网安装:Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...
基于Flask实现的医疗保险欺诈识别监测模型
基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施,由雇主和个人按一定比例缴纳保险费,建立社会医疗保险基金,支付雇员医疗费用的一种医疗保险制度, 它是促进社会文明和进步的…...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...
零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...
华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...
SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...
