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;
 });
相关推荐
abc800211703410 分钟前
前端Bug 修复手册
前端·bug
Best_Liu~13 分钟前
el-table实现固定列,及解决固定列导致部分滚动条无法拖动的问题
前端·javascript·vue.js
_斯洛伐克1 小时前
下降npm版本
前端·vue.js
苏十八2 小时前
前端进阶:Vue.js
前端·javascript·vue.js·前端框架·npm·node.js·ecmascript
st紫月3 小时前
用MySQL+node+vue做一个学生信息管理系统(四):制作增加、删除、修改的组件和对应的路由
前端·vue.js·mysql
乐容3 小时前
vue3使用pinia中的actions,需要调用接口的话
前端·javascript·vue.js
似水明俊德4 小时前
ASP.NET Core Blazor 5:Blazor表单和数据
java·前端·javascript·html·asp.net
至天5 小时前
UniApp 中 Web/H5 正确使用反向代理解决跨域问题
前端·uni-app·vue3·vue2·vite·反向代理
与墨学长5 小时前
Rust破界:前端革新与Vite重构的深度透视(中)
开发语言·前端·rust·前端框架·wasm
H-J-L5 小时前
Web基础与HTTP协议
前端·http·php