vue3 + vant移动端实现上拉刷新下拉加载

介绍

在移动端开发中,下拉刷新、上拉加载是列表类页面的核心交互需求。这里使用vant UI框架van-pull-refresh + van-list组件来实现这功能。

官网地址:https://vant.pro/vant/#/zh-CN/

核心原理

  1. 下拉刷新(van-pull-refresh):监听用户下拉手势,触发刷新逻辑,重置列表数据为第一页,完成后恢复初始状态。
  2. 上拉加载(van-list): 监听滚动容器触底事件,触发加载逻辑,加载下一页数据,直到无更多数据。
  3. 状态管理:通过loading(加载中)、finished(加载完成)、refreshing(刷新中)三个状态控制组件交互,避免重复请求。

上拉加载下拉刷新组件

页面结构

javascript 复制代码
<template>
  <van-pull-refresh
    v-model="refreshing"
    @refresh="onRefresh"
  >
    <van-list
      v-model:loading="loading"
      :finished="finished"
      :finished-text="list.length === 0 ? '' : '没有更多了'"
      @load="onLoad"
      :immediate-check="false"
    >
      <slot :list="list"></slot>
    </van-list>
  </van-pull-refresh>
</template>
<script lang="ts" setup> 
const props = defineProps({
  api: {
    type: Function,
    required: true
  },
  // 每页条数
  pageSize: {
    type: Number,
    default: 10
  }
})
const emit = defineEmits(['update:list', 'refresh'])
// 状态
const list = ref<any>([])
const pageNo = ref(1)
const loading = ref(false)
const refreshing = ref(false)
const finished = ref(false)

// 重置 & 刷新
const onRefresh = async () => {
  console.log('refresh')
  loading.value = true
  pageNo.value = 1
  finished.value = false
  try {
    await fetchData()
  } finally {
    console.log('结束+++++');
    setTimeout(() => {
      refreshing.value = false
      loading.value = false
    }, 300)
  }
  emit('refresh')
}

// 上拉加载
const onLoad = async () => {
  console.log('load')
  if (refreshing.value) return
  pageNo.value++
  await fetchData()
}

// 请求数据
const fetchData = async () => {
  try {
    const res = await props.api({
      pageNo: pageNo.value,
      pageSize: props.pageSize
    })

    if (pageNo.value === 1) {
      list.value = res.list || []
    } else {
      list.value = [...list.value, ...(res.list || [])]
    }

    // 判断是否加载完
    finished.value = list.value.length >= (res.total || 0)
  } catch(error) {
    if (pageNo.value === 1) {
      refreshing.value = false
    }
  } finally {
    loading.value = false
    emit('update:list', list.value);
  }
}

// 外部强制刷新用
const reload = async () => {
  pageNo.value = 1
  finished.value = false
  list.value = []
  await fetchData()
}

defineExpose({ reload, list })

// 初始化
fetchData()
</script>
<style lang="scss" scoped></style>

配置型

配置项 作用 推荐值
immediate-check 是否初始化时立即检测触底 false(避免页面加载时误触底)
offset 触底检测偏移量(距离底部多少像素触发加载) 100(增大偏移量减少误触)
disabled(pull-refresh) 刷新时禁用加载 绑定 loading(避免刷新和加载同时触发)

组件使用

javascript 复制代码
<RefreshList ref="refreshListRef" :api="getData">
  <template #default="{ list }">
  // 列表数据
  </template>
</RefreshList>
<script lang="ts" setup>
const getData = async ({ pageNo, pageSize }) => {
  try {
    const result = await getList({ ...formData, pageNo, pageSize })
    return {
      list: result.list,
      total: result.total
    }
  } catch (error) {
    console.log(error)
  }
}
</script>

可拖拽数据大屏项目地址

react版本:https://gitee.com/qlsgr/DataReport/

vue版本:https://gitee.com/belief-team/report

相关推荐
A923A2 小时前
【Vue3大事件 | 项目笔记】第一天
前端·vue.js·笔记·前端框架
钰衡大师2 小时前
Vue 3 源码阅读笔记:ref.ts
javascript·vue.js·笔记·vue3源码阅读
前端小菜鸟也有人起2 小时前
Vue3父子组件通信方法总结
前端·javascript·vue.js
z止于至善3 小时前
Vue ECharts:Vue 生态下的 ECharts 可视化最佳实践
前端·vue.js·echarts·vue echarts
Software攻城狮3 小时前
【el-table 表格组件 删除标头分割线】
前端·vue.js·elementui
陆康永3 小时前
vue2封装hook函数,可以监听主页面生命周期
前端·javascript·vue.js
我命由我123453 小时前
Vue Router - 记录一下 2 种路由写法
前端·javascript·vue.js·前端框架·html·html5·js
m0_719084113 小时前
导入导出—设备管理系统
前端·javascript·vue.js