vue3.0 + vant实现下拉刷新上拉加载

在vue中使用vant组件库有个van-pull-refresh下拉组件,配合van-list列表组件实现页面的下拉刷新和上拉加载,原理简单,适用场景在列表页面内容展示。

下拉刷新

PullRefresh 实现下拉刷新的效果。

PullRefresh组件中的searchRefreshing属性,是下拉刷新时专用的,值有两个true/false;

searchRefreshing设置为true,表示下拉刷新完毕,列表顶部的"加载中..."会隐藏;

searchRefreshing设置为false,表示正在下拉刷新,列表顶部的"加载中..."会显示

参数说明

参数 说明 类型 默认值
v-model 是否处于加载中状态 boolean -
pulling-text 下拉过程提示文案 string 下拉即可刷新...
loosing-text 释放过程提示文案 string 释放即可刷新...
loading-text 加载过程提示文案 string 加载中...
success-text 刷新成功提示文案 string -
success-duration 刷新成功提示展示时长(ms) number或 string 500
animation-duration 动画时长 number或 string 300
head-height 顶部内容高度 number 或 string 50
pull-distance 触发下拉刷新的距离 number 或 string 与 head-height 一致
disabled 指是否禁用下拉刷新 boolean false

事件说明

事件名 说明 回调参数
refresh 下拉刷新时触发 -
change 拖动时或状态改变时触发 { status: string, distance: number }

插槽说明

名称 说明 参数
default 自定义内容 -
normal 非下拉状态时顶部内容 -
pulling 下拉过程中顶部内容 { distance: number }
loosing 释放过程中顶部内容 { distance: number }
loading 加载过程中顶部内容 { distance: number }
success 刷新成功提示内容 -

上拉加载

List 组件实现上拉加载的效果

List通过loading和finished两个变量控制加载状态,当组件滚动到底部时,会触发load事件并将loading设置成true。此时可以发起异步操作并更新数据,数据更新完毕后,将loading设置成false即可。若数据已全部加载完毕,则直接将finished设置成true即可。

注意事项:

  • v-model : 是否处于加载状态,加载过程中不触发load事件
  • finished: 是否已加载完成,加载完成后不再触发load事件
  • offset : 滚动条与底部距离小于 offset 时触发load事件
  • loading-text加载过程中的提示文字
  • finished-text加载完成后的提示文字

List有以下三种状态,理解这些状态有助于你正确地使用List组件:

  1. 非加载中,loading为false,此时会根据列表滚动位置判断是否触发load事件(列表内容不足一屏幕时,会直接触发)
  2. 加载中,loading为true,表示正在发送异步请求,此时不会触发load事件
  3. 加载完成,finished为true,此时不会触发load事件

在每次请求完毕后,需要手动将loading设置为false,表示加载结束

事件使用:@load方法

滚动条与底部距离小于 offset 时触发

属性说明

参数 说明 类型 默认值
v-model:loading 是否处于加载状态,加载过程中不触发 load 事件 boolean false
v-model:error 是否加载失败,加载失败后点击错误提示可以重新触发 load 事件 boolean false
finished 是否已加载完成,加载完成后不再触发 load 事件 boolean false
offset 滚动条与底部距离小于 offset 时触发 load 事件 number& string 300
loading-text 加载过程中的提示文案 string 加载中...
finished-text 加载完成后的提示文案 string -
error-text 加载失败后的提示文案 string -
immediate-check 是否在初始化时立即执行滚动位置检查 boolean true
disabled 是否禁用滚动加载 boolean false
direction 滚动触发加载的方向,可选值为 up string down
scroller v4.6.4 指定需要监听滚动事件的节点,默认为最近的父级滚动节点 Element -

事件

事件名 说明 回调参数
load 滚动条与底部距离小于 offset 时触发 -

方法

方法名 说明 参数 返回值
check 检查当前的滚动位置,若已滚动至底部,则会触发 load 事件 - -

完整代码示例

cpp 复制代码
<template>
  <div>
    <div v-if="listArr.length > 0">
      <PullRefresh v-model="isLoading" @refresh="handleRefresh">
        <List
          v-model:loading="loading"
          :finished="finishedStatus"
          :offset="80"
          finished-text="没有更多了"
          @load="handleLoad"
          error-text="请求失败,点击重新加载"
          :scroller="scrollerBody"
          :immediate-check="false"
        >
          <CellGroup v-for="item in listArr" style="margin-bottom: 10px" :key="item.id" inset border>
            <Cell>
              <template #title>
                <span class="custom-title">条码号:&nbsp;</span>
                <span>{{ item.packageCode }}</span>
              </template>
            </Cell>
            <div class="contentDesc">
              <div class="entryDesc"
                ><span>需求来源:</span><span>{{ item.receiveCode }}</span></div
              >
              <div class="entryDesc">
                <span>激活状态:</span><span>{{ item.printStatus_dictText }}</span>
              </div>
              <div class="entryDesc">
                <span>单号:</span><span>{{ item.skuCode }}</span>
              </div>
              <div class="entryDesc"
                ><span>打印日期:</span><span>{{ item.printDate }}</span></div
              >
            </div>
          </CellGroup>
        </List>
      </PullRefresh>
    </div>
  </div>
</template>
<script lang="ts">
  import { defineComponent, ref, onMounted, computed, reactive, toRefs } from 'vue';
  import { Icon, Divider, Row, Cell, CellGroup, Dialog, Button, Picker, Field, Calendar, Form, PullRefresh, List, Popup } from 'vant';
  import 'vant/lib/index.css';
  import { PrintCode, PagePrintCode } from './print.data';
  import { QrCode } from '/@/components/Qrcode/index';
  import { useRouter, useRoute } from 'vue-router';
  import { list } from '/@/views/wcs/PrintCodeList/PrintCode.api';

  export default defineComponent({
    // 若需要开启页面缓存,请将此参数跟菜单名保持一致
    name: 'LargePackageCode',
    components: {
      Icon,
      Divider,
      Cell,
      CellGroup,
      Picker,
      Calendar,
      Field,
      Form,
      Button,
      PullRefresh,
      List,
      Dialog,
      QrCode,
      Popup,
      Row,
    },
    setup() {
      const { replace } = useRouter();
      const route = useRoute();
      let isLoading = ref<boolean>(false);
      let loading = ref<boolean>(false);
      let finishedStatus = ref<boolean>(false);
      let listArr = ref<PrintCode[]>([{}]);
      let pageNo = ref<number>(1);
      let pageSize = ref<number>(10);
      let totalItems = ref<number>(0);
      let showDialog = ref(false);
      const state = reactive({
        receiveCode: '',
      });
      onMounted(() => {
        listArr.value = [];
        getInfo('');
      });
      const scrollerBody = computed(() => {
        return document.body;
      });
      async function getInfo(status) {
        let data: PagePrintCode = await list({
          pushDate: '', //	推送日期	query	false
          receiveCode: state.receiveCode, //	收货单号	query	false
          status: status, //	状态
          pageNo: pageNo.value, //	pageNo,示例值(1)	query	false
          pageSize: pageSize.value, //	pageSize,示例值(10)	query	false
          column: 'createTime',
          order: 'desc',
        });
        totalItems.value = data.total as 0;
        let arr = data.records as [];
        listArr.value = listArr.value.concat(arr);
        loading.value = false;
        const num = listArr.value.length - totalItems.value;
        if (num >= 0) {
          finishedStatus.value = true;
        }
      }
      async function handleRefresh() {
        pageNo.value = 1;
        isLoading.value = false;
        await getInfo('');
        // 清空列表数据
        finishedStatus.value = false;
      }
      function handleLoad() {
        // loading.value = true;
        setTimeout(() => {
          if (isLoading.value) {
            listArr.value = [];
            isLoading.value = false;
          }
          // 数据全部加载完成
          pageNo.value++;
          getInfo('');
        });
      }
      return {
        ...toRefs(state),
        listArr,
        totalItems,
        isLoading,
        loading,
        finishedStatus,
        showDialog,
        handleRefresh,
        handleLoad,
        scrollerBody,
      };
    },
  });
</script>
<style lang="less" scoped>
  .contentDesc {
    padding: 10px 16px;
    color: #969799;

    .entryDesc {
      display: flex;
      justify-content: space-between;
      padding: 2px;
      align-items: center;
    }
  }
</style>

bug

在@load事件不生效,在滚动的过程中,onLoad事件没有任何反应,项目中vant版本 "vant": "^4.9.1"

若不设置要设置父元素css属性 style="{height: 100vh; over; overflow-y: scroll;}",但是这样设置会有2个滚动条,一个是List父元素的,一个是body的,很难看

这个时候就考虑scroller属性,指定需要监听滚动事件的节点到body元素上,这时就会只出现一个滚动条,onLoad事件也触发了。

cpp 复制代码
// template 中设置
<List
   v-model:loading="loading"
   :finished="finishedStatus"
   :offset="80"
   finished-text="没有更多了"
   @load="handleLoad"
   error-text="请求失败,点击重新加载"
   :scroller="scrollerBody"
   :immediate-check="false" 
  >
  // :immediate-check="false"  设置首次不加载
     ....
  </List>
//  ts中设置
 const scrollerBody = computed(() => {
   return document.body;
 });
相关推荐
ziyue75755 分钟前
vue修改element-ui的默认的class
前端·vue.js·ui
树叶会结冰26 分钟前
HTML语义化:当网页会说话
前端·html
冰万森32 分钟前
解决 React 项目初始化(npx create-react-app)速度慢的 7 个实用方案
前端·react.js·前端框架
牧羊人_myr1 小时前
Ajax 技术详解
前端
浩男孩1 小时前
🍀封装个 Button 组件,使用 vitest 来测试一下
前端
蓝银草同学1 小时前
阿里 Iconfont 项目丢失?手把手教你将已引用的 SVG 图标下载到本地
前端·icon
布列瑟农的星空1 小时前
重学React —— React事件机制 vs 浏览器事件机制
前端
程序定小飞2 小时前
基于springboot的在线商城系统设计与开发
java·数据库·vue.js·spring boot·后端
一小池勺2 小时前
CommonJS
前端·面试