当前位置: 首页 > article >正文

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

目录

  • 一,功能介绍
  • 二,思路介绍
  • 三,关键点
    • 1.触底条件
    • 2.判断什么时候发起请求
  • 四,组件参数及解释
  • 五,整体代码
  • 后记

一,功能介绍

本文是基于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条,因为要产生滚动的触发条件。
在这里插入图片描述

五,整体代码

<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>

后记

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


http://www.kler.cn/a/379958.html

相关文章:

  • B2109 统计数字字符个数
  • SpringBoot新闻稿件管理系统:架构与实现
  • C# 日志框架 NLog、log4net 和 Serilog对比
  • linux系统安装git及git常用命令
  • nodejs入门教程19:nodejs dns模块
  • channel error 报错【已解决】
  • [C++]使用cpphttplib的http服务上传和下载
  • golang运行某个类下所有的基准测试
  • 得物多模态大模型在重复商品识别上的应用和架构演进
  • Django ORM详解: model转字典的几种方法
  • 1.3 初探OpenCV贡献库
  • c++中string底层实现之SSO
  • DMFLDR数据载入使用实践
  • 【Git】Git 远程仓库命令详解
  • three.js 实现 css2d css3d效果 将 二维Dom 和 三维场景结合
  • Oracle 第18章:分区技术
  • 代理IP地址和端口是什么?怎么进行设置?
  • 嵌入式开发之文件I/O-函数
  • 在区块链技术中,什么是权益证明(PoS)?
  • 从 TCP 友好性看传输优化
  • 快速入门CSS
  • flutter dart mixin 姿势
  • 【VS+QT】联合开发踩坑记录
  • 【毫米波雷达(七)】自动驾驶汽车中的精准定位——RTK定位技术
  • 【视频】OpenCV:识别颜色、绘制轮廓
  • Docker 部署RocketMQ