微信小程序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. 滚动位置维护

参考资料

相关推荐
快乐的二进制鸭4 小时前
uniapp实现app的pdf预览
pdf·uni-app
爱学习的小王!4 小时前
nvm安装、管理node多版本以及配置环境变量【保姆级教程】
经验分享·笔记·node.js·vue
盛夏绽放5 小时前
微信小程序地图map全方位解析
微信小程序·小程序
qq_316837755 小时前
uniapp 打包安卓 集成高德地图
uni-app
阿福的工作室5 小时前
uniapp录制语音
uni-app
初尘屿风7 小时前
基于微信小程序的电影院订票选座系统的设计与实现,SSM+Vue+毕业论文+开题报告+任务书+指导搭建视频
vue.js·微信小程序·小程序
貂蝉空大8 小时前
uni-app开发app时 使用uni.chooseLocation遇到的问题
uni-app
林同学++8 小时前
uniapp多端适配
uni-app
kidding7238 小时前
uniapp引入uview组件库(可以引用多个组件)
前端·前端框架·uni-app·uview
qq_316837758 小时前
uniapp 安卓10+ 选择并上传文件
uni-app