微信小程序uni-app+vue3实现局部上下拉刷新和scroll-view动态高度计算

微信小程序uni-app+vue3实现局部上下拉刷新和scroll-view动态高度计算

前言

在uni-app+vue3项目开发中,经常需要实现列表的局部上下拉刷新功能。由于网上相关教程较少且比较零散,本文将详细介绍如何使用scroll-view组件实现这一功能,包括动态高度计算、下拉刷新、上拉加载等完整实现。

重要提示

⚠️ triggered状态管理是关键

  • triggered必须手动管理其true/false状态
  • 不正确的状态管理会导致下拉刷新卡住
  • 需要在适当的时机重置状态

核心实现思路

  1. 状态定义
typescript 复制代码
// 下拉刷新相关状态
const triggered = ref(false)                 // 触发下拉刷新状态
const refresherEnabled = ref(true)           // 是否启用下拉刷新
  1. 关键事件处理
typescript 复制代码
// 下拉过程中触发
const onPulling = () => {
  triggered.value = true  // 手动设置为true
}

// 刷新结束时触发
const onRestore = () => {
  triggered.value = false  // 手动重置为false
}

// 刷新中断时触发
const onAbort = () => {
  triggered.value = false  // 手动重置为false
}

// 刷新数据处理
const refreshHistoryList = async () => {
  triggered.value = true  // 开始刷新时设置为true
  try {
    // 执行刷新逻辑
    await loadData()
  } catch (err) {
    console.error('刷新失败:', err)
  } finally {
    triggered.value = false  // 完成后一定要设置为false
  }
}
  1. 组件配置
vue 复制代码
<scroll-view
  :refresher-enabled="refresherEnabled"
  :refresher-triggered="triggered"
  @refresherrefresh="refreshHistoryList"
  @refresherpulling="onPulling"
  @refresherrestore="onRestore"
  @refresherabort="onAbort"
>
  <!-- 列表内容 -->
</scroll-view>

注意事项

  1. 状态重置时机

    • 刷新完成时必须重置
    • 刷新中断时必须重置
    • 组件卸载时最好重置
  2. 常见问题

    • 忘记重置导致卡住
    • 重置时机不对导致异常
    • 多个事件重复设置状态
  3. 最佳实践

    • 使用try/finally确保重置
    • 统一状态管理位置
    • 添加适当的错误处理

快速开始

1. 基础配置

2. 组件结构

在template中创建scroll-view组件:

vue:src/pages/analyzeTable/index.vue 复制代码
<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 - 组件的引用标识
typescript 复制代码
// 下拉刷新相关
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. 动态高度计算

typescript 复制代码
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 - 40
    scrollViewHeight.value = `${scrollHeight}rpx`
  })
})

核心功能实现

1. 下拉刷新

typescript 复制代码
// 下拉刷新处理
const refreshHistoryList = async () => {
  triggered.value = true
  currentPage.value = 1
  
  try {
    const res = await loadFirstPage()
    list.value = res.data
    updateLoadStatus()
  } catch (err) {
    console.error('刷新失败:', err)
  } finally {
    triggered.value = false
  }
}

2. 上拉加载

typescript 复制代码
// 上拉加载更多
const loadmore = async () => {
  if (scrollStatus.value === 'noMore') return
  
  scrollStatus.value = 'loading'
  try {
    const res = await loadMoreData(++currentPage.value)
    list.value.push(...res.data)
    updateLoadStatus()
  } catch (err) {
    console.error('加载失败:', err)
    scrollStatus.value = 'loadmore'
  }
}

3. 滚动事件处理

typescript 复制代码
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.height
  if (scrollBottom < 50 && scrollStatus.value === 'loadmore') {
    loadmore()
  }
}

注意事项

  1. 高度计算

    • 需要考虑所有固定元素的高度
    • 使用rpx单位确保跨设备兼容性
    • 预留适当边距避免内容被遮挡
  2. 性能优化

    • 使用enable-passive提升滚动性能
    • 合理控制刷新频率
    • 避免频繁触发加载更多
  3. 用户体验

    • 添加加载提示
    • 保持滚动位置
    • 合理控制刷新触发时机

加载更多组件使用

⚠️ up-loadmore组件使用说明

  1. 基础配置
vue 复制代码
<up-loadmore 
  v-if="list.length>0" 
  :status="scrollStatus" 
  @loadmore="loadmore"
  loadmore-text="加载更多"
/>
  1. 状态管理
typescript 复制代码
// 加载状态
const scrollStatus = ref<string>('loadmore') // 可选值: loadmore/loading/noMore

// 加载更多处理
const loadmore = async () => {
  if (scrollStatus.value === 'noMore') return
  
  scrollStatus.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'
  }
}
  1. 触发方式
  • 通过@loadmore事件监听触发加载
  • 可以在scroll-view滚动到底部时自动触发
  • 也可以点击"加载更多"文本手动触发
  1. 状态说明
  • loadmore: 可以加载更多
  • loading: 正在加载中
  • noMore: 没有更多数据

完整示例

vue 复制代码
<scroll-view 
  @scroll="roll"
  :scroll-y="true"
>
  <!-- 列表内容 -->
  <view v-for="(item, index) in list" :key="index">
    {{ item }}
  </view>
  
  <!-- 加载更多组件 -->
  <up-loadmore
    v-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.height
  if (scrollBottom < 50 && scrollStatus.value === 'loadmore') {
    loadmore()
  }
}

// 加载更多处理
const loadmore = async () => {
  if (scrollStatus.value === 'noMore') return
  scrollStatus.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>

总结

通过本教程的学习,我们掌握了:

  1. scroll-view组件的基本使用
  2. 动态高度计算方法
  3. 下拉刷新实现
  4. 上拉加载更多功能
  5. 滚动位置维护

参考资料

相关推荐
hello kitty w6 分钟前
2. 微信开发工具快捷键
小程序
计算机毕设指导610 分钟前
基于微信小程序的丽江市旅游分享系统【源码文末联系】
java·spring boot·微信小程序·小程序·tomcat·maven·旅游
1024小神43 分钟前
浏览器或小程序限制字体最小12px解决办法
小程序
内存不泄露1 小时前
酒店预订管理平台及小程序
小程序
2501_915918412 小时前
除了 Perfdog,如何在 Windows 环境中完成 iOS App 的性能测试工作
android·ios·小程序·https·uni-app·iphone·webview
爱学英语的程序员2 小时前
让AI 帮我做了个个人博客(附提示词!)
人工智能·git·vue·github·node·个人博客
丢,捞仔2 小时前
uni-app上架应用添加权限提示框
前端·javascript·uni-app
weixin_lynhgworld2 小时前
[特殊字符]短剧小程序开发:开启娱乐新纪元的钥匙[特殊字符]
小程序
程序媛徐师姐2 小时前
Java基于微信小程序的鲜花销售系统,附源码+文档说明
java·微信小程序·鲜花销售小程序·java鲜花销售小程序·鲜花销售微信小程序·java鲜花销售系统小程序·java鲜花销售微信小程序
五仁火烧3 小时前
Vite和HTTP 服务器
服务器·网络协议·http·vue