基于ant组件库挑选框组件-封装滚动刷新的分页挑选框

目录

一,功能介绍

本文是基于ant组件库的select组件进行封装:
ant组件库选择器Select组件

在开发中,由于挑选框数据过多,一次加载全部数据展示在前端可能会导致数据卡顿,卡顿的主要原因有两个:第一是向后端请求大量数据,这个过程需要时间;第二是前端如果一次性渲染多个dom会导致页面卡顿。

研究了ant和element组件库后发现,其实它们的下拉框都有做虚拟列表,一次性只渲染十个dom,因此在组件库的基础上封装,我们只需要解决第一个问题,需要后端提供分页接口,前端展示固定条数据,再次下划后调用分页接口。再利用其组件库自带的虚拟列表来优化性能。

二,思路介绍

这里是基于ant组件库,但是放到element上思路其实类似。

ant组件库的下拉框,一条数据的高度大概是32px,我们也可也根据自己设置的样式高度来自定义。这里为什么要提到高度,因为是根据当前渲染的高度来判断目前到了第几条数据。假如我们一次性展示10条数据(展示页数尺寸是10条一页),那么高度触底为大概320px的时候我们需要调用接口请求下一页的数据。

这里有一个问题,每一次请求,分页的长度为多少?我封装的是11,设想第一次请求,一共11条数据,展示10条,想要加载全部需要下划滚动,所以才有可能触发下拉这个方法。如果设置一条展示10条,且分页请求只有10条的话,第一次加载时刚好占满盒子高度,无法触发分页请求。

如果需要搜索功能,可以在分页封装完之后,写搜索查询的事件。只需要加上对应字段就好,逻辑也是遵循刚写的分页逻辑的。

三,关键点

1.触底条件

用到的是组件库的这个方法:

触底条件:

如果:滚动距离 + 元素的垂直高度 === 容器高度(滚动到底部)则为触底。

2.判断什么时候发起请求

如果触底,且当前长度 < 数据总长度,则发起请求。为什么是size+1,在上一节已经给出了解释。

四,组件参数及解释

组件的封装在于复用,使用组件,需要传进去的有代表label和value的字段,请求函数,每一页的长度(分页长度)以及搜索字段。

传进去的如果是10,展示10条,也就是320px左右(如果有改样式需要自行定义32,这个值也可也考虑作为参数);但是实际上发起请求是11条,因为要产生滚动的触发条件。

五,整体代码

javascript 复制代码
<script setup lang="ts">
  import { selectProps } from 'ant-design-vue/es/vc-select';

  // 该组件的作用是下拉框下拉更新,用于分页接口的下拉框,仅针对不修改样式的ant下拉框
  const props = defineProps({
    ...selectProps,
    width: {
      type: Number,
      default: 200,
    },
    // label字段
    label: {
      type: String,
      default: '',
    },
    // value字段
    value: {
      type: String,
      default: '',
    },
    // 分页请求
    request: {
      type: Function,
      default: () => {
        return {
          data: '',
          success: false,
        };
      },
    },
    // 每页长度(展示多少条数据后下拉更新第二页)
    size: {
      type: Number,
      default: 10,
    },
    // 搜索字段
    searchName: {
      type: String,
      default: '',
    },
  });

  // 返回值-可有可无
  const resultValue = defineModel('resultValue', {
    type: String,
    default: '',
  });

  // 下拉展示数据
  const selectOption = ref([]);
  // 总数据长度
  const selectTotal = ref(0);

  // 获取下拉框列表信息
  const getSelectOptions = async (current, size, searchVal?) => {
    const { data } = await props.request({
      current: current || '1',
      size: size || props.size + 1,
      keyword: searchVal ?? '',
    });
    return data;
  };

  // 初始状态至少要多请求一个,因为加入有大于size的数据,只展示size个,就不会有滚动条
  // 想要有滚动条数据的量要大于展示量
  onMounted(async () => {
    const data = await getSelectOptions(1, props.size + 1);
    // 处理data
    selectOption.value = data.records.map((item) => {
      return {
        label: item[props.label],
        value: item[props.value],
      };
    });
    // 总长度
    selectTotal.value = data.total;
  });

  // 找个值来接收搜索框文本
  const searchVal = ref('');
  const popup = async (e) => {
    const { target } = e;
    // 如果触底
    if (target.scrollTop + target.offsetHeight === target.scrollHeight) {
      // 先做一个判断
      if (selectOption.value.length < selectTotal.value) {
        // 如果数据还没有加载出来,请求当前页的后一页
        const data = await getSelectOptions(
          selectOption.value.length / (props.size + 1) + 1,
          props.size + 1,
          searchVal.value ?? '',
        );
        const selectOptionAdd = data.records.map((item) => {
          return {
            label: item[props.label],
            value: item[props.value],
          };
        });
        selectOption.value = [...selectOption.value, ...selectOptionAdd];
      }
    }
  };

  const searchChange = async (val) => {
    searchVal.value = val;
    const data = await getSelectOptions(1, props.size + 1, val);
    selectOption.value = data.records.map((item) => {
      return {
        label: item[props.label],
        value: item[props.value],
      };
    });
    selectTotal.value = data.total;
  };
</script>

<template>
  <a-select
    ref="select"
    v-model:value="resultValue"
    :options="selectOption"
    :list-height="size * 32"
    :filter-option="false"
    :style="{ width: `${width}px` }"
    @popup-scroll="popup"
    @search="searchChange"
  ></a-select>
</template>

后记

感谢阅读,期望获取关注,博客会持续更新。

相关推荐
小扳19 分钟前
Web 毕设篇-适合小白、初级入门练手的 Spring Boot Web 毕业设计项目:电影院后台管理系统(前后端源码 + 数据库 sql 脚本)
java·前端·数据库·spring boot·mysql·spring·课程设计
田本初19 分钟前
从0-1逐步搭建一个前端脚手架工具并发布到npm
前端·npm·node.js
Marshall35721 小时前
Canvas 和 SVG 的高级使用与性能优化
前端·svg·canvas
chusheng18402 小时前
Java基于SpringBoot+Vue的藏区特产销售平台
java·vue.js·spring boot·藏区特产销售平台·特产销售平台
Java学长-kirito2 小时前
springboot/ssm网购平台管理系统Java在线购物商城管理平台web电商源码
java·前端·spring boot
夫琅禾费米线2 小时前
JavaScript 中的 Generator 函数及其方法
开发语言·前端·javascript
Traced back2 小时前
pinia的使用
前端
世界和平�����2 小时前
vue3 命名式(函数式)弹窗
前端·javascript·vue.js
所遇所思2 小时前
vue项目中中怎么获取环境变量
前端·javascript·vue.js
ljklxlj2 小时前
webview4/edgewebbrower学习记录——执行js
前端·javascript·学习