ant-design-vue中 a-select组件 - 加载大量数据造成卡顿--已解决

解决方案借鉴 列表的滚动加载,实现 a-select 数据展示时滚动加载

隐藏问题:

在ant-design-vue 中 ,select 可以通过 输入文字 匹配 数据源中的数据,但是在滚动加载中,如果暂时还没有加载到该条数据,则不能 匹配 到的这条数据。

具体思路如下:

  1. 监听下拉框展开,下拉框展开后,要重置展示的数据,默认每一次新展开就回到初始加载的数据展示。
  2. 监听数据滚动 - @popupScroll
  3. 滚动条改变后 请求数据加载(可以异步请求,也可以一次性请求后,分批加载)
  4. 对滚动加载 做 防抖处理,限制多次请求(lodash/debounce)
  5. 更新下拉框的数据,需要判断已渲染的下拉长度和当前数据源(总数据)的长度,然后 .concat 拼接数组

但这样会有一个隐藏问题,隐藏问题放在最后再说。根据思路解决 “大量数据加载造成的卡顿” 的问题吧。

前置

  • 引入 ant-design-vue ,注意引入的版本,可参考官方说明
    npm i --save ant-design-vue@next

  • 引入  lodash 
     npm i --save lodash
  • 按需引入 ant-design-vue  中的 Select 组件
    // 引入ant-design-vue 的样式
    import 'ant-design-vue/dist/antd.css';
    // 按需引入 Select 组件
    import { Select } from "ant-design-vue";
    
    const app = createApp(App)
    
    app.use(Select)
    
    app.use(store).use(router).mount("#app");

template

    <!--
      allowClear : 支持清除		false:不清除	
      mode :	设置 Select 的模式为多选或标签	'multiple' | 'tags' | 'combobox'
      show-search 	可输入关键词后,对下拉框数据进行搜索
      popupScroll : 下拉列表滚动时的回调
      change : 选中 option,或 input 的 value 变化(combobox 模式下)时,调用此函数
      dropdownVisibleChange : 展开下拉菜单的回调
     -->
    <a-select
      :allowClear="true"
      mode="multiple"
      style="width: 200px"
      placeholder="请选择"
      showArrow
      show-search
      @popupScroll="handlePopupScroll"
      @change="handleChange"
      @dropdownVisibleChange="handleDropdownVisibleChange"
    >
      <a-select-opt-group v-for="item in showList" :key="item">
        <template #label>
          <span> {{ item.letter }} </span>
        </template>
        <a-select-option
          v-for="item in item.letter_arr"
          :key="item"
          :value="item"
          @click="handleClickChange(item)"
          >{{ item }}</a-select-option
        >
      </a-select-opt-group>
    </a-select>

 JS

import { reactive, toRefs } from "vue";
import debounce from "lodash/debounce";
/**
 * 
 * all_Data: 总数据
 * showList:用来展示在 select 下拉框中的数据
 * handlePopupScroll:select 下拉框中的滚动条 滚动时 的回调,做防抖处理
 * handleDropdownVisibleChange:select 下拉框 展开时 的回调监听,open===true,即展开下拉框
 * loadMoreData:滚动条滚动时,showList加载 all_Data 中的数据,更新下拉框的数据
 * handleChange:获取 点击选中的 数据
 * 
*/
export default {
  name: "Home",
  setup() {
    const home_reac = reactive({
      all_Data: [
        {
          letter: "A",
          letter_arr: [
            "a_1",
            "a_2",
            "a_3",
            "a_4",
            "a_5",
            "a_6",
            "a_7",
            "a_8",
            "a_9",
            "a_10",
          ],
        },
        {
          letter: "B",
          letter_arr: [
            "b_1",
            "b_2",
            "b_3",
            "b_4",
            "b_5",
            "b_6",
            "b_7",
            "b_8",
            "b_9",
            "b_10",
          ],
        },
        {
          letter: "C",
          letter_arr: [
            "c_1",
            "c_2",
            "c_3",
            "c_4",
            "c_5",
            "c_6",
            "c_7",
            "c_8",
            "c_9",
            "c_10",
          ],
        },
        {
          letter: "D",
          letter_arr: [
            "d_1",
            "d_2",
            "d_3",
            "d_4",
            "d_5",
            "d_6",
            "d_7",
            "d_8",
            "d_9",
            "d_10",
          ],
        },
        {
          letter: "E",
          letter_arr: [
            "e_1",
            "e_2",
            "e_3",
            "e_4",
            "e_5",
            "e_6",
            "e_7",
            "e_8",
            "e_9",
            "e_10",
          ],
        },
      ],
      showList: [],
    });

    // select - 滚动条 回调 - select数据请求
    const handlePopupScroll = debounce(function () {
      loadMoreData(home_reac.all_Data);
    }, 400);

    // 下拉框打开时 的 回调
    const handleDropdownVisibleChange = (open) => {
      if (open) {
        // 下拉框打开时重置展示的数据
        home_reac.showList = home_reac.all_Data.slice(0, 1);
      }
    };

    // 更新下拉框 展示  的 数据
    const loadMoreData = (dataList) => {
      // 已渲染的下拉列表长度
      const length = home_reac.showList.length;
      // 当前数据源的长度
      const total = dataList.length;
      // 新加载的数据
      let addList = [];
      if (length < total) {
        if (length + 1 <= total) {
          addList = dataList.slice(length, length + 1);
        } else {
          addList = dataList.slice(length, length + (total % 1));
        }
        // 更新下拉框展示的数据
        home_reac.showList = home_reac.showList.concat(addList);
      }
    };

    //数据 筛选
    const handleChange = (item) => {
      console.log("数据筛选", item);
    };

    return {
      ...toRefs(home_reac),
      handlePopupScroll,
      handleChange,
      handleDropdownVisibleChange,
    };
  },
};

这次真是一点也没保留代码,完整的都在这里了~

对了,还有一个隐藏问题,就是:

由于数据是动态加载,当我们第一次请求展示的数据为 “A” 开头的,

此时下拉框中的数据为 A数组 的全部,

那在 input 框中输入关键词搜索时,

将搜索不到 A 以外的其他数据

解决方法暂时有一个方案,但是还没有试验,就是:

当展开下拉框的时候,通过定时器来请求数据,不通过滚动操作来请求加载。

当然,这个方法还没有试验,不确定能不能解决这个问题。 

欢迎关注公众号 “DataShow Charts”呀,我也会在公众号同步发布本篇文章,源码在公众号中~

<think> 嗯,用户的问题是关于ant-design-vue的a-select组件在使用虚拟滚动时丢失底部选项的解决方法。从用户提供的引用来看,ta应该已经尝试过一些优化方案,比如引用[3]提到的filterOption配置和引用[5]的模糊搜索实现,但核心问题在于虚拟滚动的显示异常。 用户可能正在开发一个需要处理大量数据的后台管理系统,遇到下拉列表渲染不全的技术瓶颈。ta的语气比较急切,引用中提到的"隐藏问题"(引用[1])很可能就是指这个滚动丢失问题。需要特别注意两个技术细节:一是虚拟滚动的实现原理,二是antd的下拉菜单渲染机制。 从技术角度分析,虚拟滚动丢失底部选项通常是因为容器高度计算偏差。引用[4]提到的getPopupContainer方案其实提供了重要线索——当选择框嵌套在可滚动容器内时,下拉菜单的定位会受到父级影响。不过用户的问题更聚焦在虚拟滚动本身,所以需要补充三点解决方案: 第一是确保使用官方推荐的虚拟滚动组件v-virtual-scroll(但antd-vue文档未明确说明),这点在引用[5]的模糊搜索示例中有所体现但不够完善。第二是动态高度问题,引用[3]设置label的方案可能影响虚拟滚动计算。第三要特别注意在异步加载数据时需要用nextTick等待DOM更新,这点所有引用都未提及但很关键。 考虑到用户已经查阅过优快云博客(引用[3]),解决方案需要比网络博客更系统。应该强调listHeight和scrollTop的联动逻辑,这是虚拟滚动的核心算法。另外引用[2]提到的Ant-Design-Vue设计体系也提醒我们,定制组件时要注意保持整体风格统一。 最后生成的延伸问题要覆盖用户可能遇到的衍生场景:比如当数据量继续增大时的分页加载方案(引用[1]提到的卡顿问题延伸),以及移动端适配(引用[4]的定位问题变种)。这样既解决当前技术瓶颈,又预防后续问题。 </think> 针对 `a-select` 组件在虚拟滚动模式下丢失底部选项的问题,可通过以下方案解决--- ### **原因分析** Ant Design Vue 的虚拟滚动(Virtual Scroll)通过动态计算可见区域高度渲染选项,若出现底部选项丢失,通常由以下原因导致: 1. **容器高度计算偏差**:滚动容器高度未正确识别 2. **动态内容未触发重绘**:数据更新后未重新计算滚动区域 3. **边界条件处理缺陷**:滚动至底部时未加载最后几项 --- ### **解决方案** #### 1. **强制更新滚动容器** 为 `a-select` 添加监听器,数据加载完成后手动更新虚拟滚动: ```vue <a-select :virtual-scroll="true" @dropdownVisibleChange="handleDropdownOpen" > <!-- 选项 --> </a-select> <script> import { nextTick } from &#39;vue&#39;; export default { methods: { async handleDropdownOpen(open) { if (open) { await nextTick(); // 触发虚拟滚动重计算 this.$refs.selectRef?.scrollTo({ top: 0 }); } } } } </script> ``` #### 2. **启用精确高度模式** 设置 `virtual-scroll` 的精确高度参数 `height`: ```vue <a-select :virtual-scroll="{ height: 256, // 固定高度(单位px) itemSize: 32 // 每项高度(单位px) }" > <a-select-option v-for="item in list" :key="item.id" :value="item.id" > {{ item.label }} </a-select-option> </a-select> ``` #### 3. **使用 `getPopupContainer` 修正定位** 防止嵌套滚动容器导致计算错误: ```vue <a-select :getPopupContainer="trigger => trigger.parentNode" > <!-- 选项 --> </a-select> ``` #### 4. **动态数据加载后重置滚动** 数据更新时重置滚动位置: ```js // 数据加载完成后 loadData().then(() => { nextTick(() => { const select = document.querySelector(&#39;.ant-select-dropdown&#39;); if (select) select.scrollTop = 0; }); }); ``` --- ### **关键配置说明** | 参数 | 类型 | 作用 | 示例值 | |--------------------|----------|-------------------------------|---------------| | `virtual-scroll` | Boolean/Object | 启用虚拟滚动 | `{ height: 300, itemSize: 32 }` | | `getPopupContainer`| Function | 指定滚动容器 | `trigger => trigger.parentNode` | | `height` (虚拟滚动) | Number | 下拉菜单可视区域高度 | `256` | | `itemSize` | Number | 每个选项的高度(像素) | `32` | --- ### **延伸问题** 1. 如何优化超大数据量(10万+)下的虚拟滚动性能?[^5] 2. 虚拟滚动与搜索过滤(`showSearch`)同时使用时有哪些注意事项?[^3][^5] 3. 移动端环境下如何适配 `a-select` 的虚拟滚动?[^4] 4. 异步加载数据时如何避免虚拟滚动白屏?[^1] > 提示:虚拟滚动需严格保证 `itemSize` 的准确性,动态高度的选项需使用 `height` + `dynamicSizeGetter` 组合方案。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值