antd的select下拉框因为数据量太大造成卡顿的解决方式


Posted in Javascript onOctober 31, 2020

相信用过antd的同学基本都用过select下拉框了,这个组件数据量少的时候很好用,但是当数据量大的时候,比如大几百条上千条甚至是几千条的时候就感觉一点都不好用了,卡的我怀疑人生,一点用户体验都没有了。

当然这不是我想去优化它的动力,主要是公司业务人员和后端的同事也无法忍受,于是我只能屈从于他们的淫威。。。。

想要优化肯定要知道为什么会卡,初步判断就是数据量过大导致渲染option组件的时间过长导致卡顿,于是想要不卡只能限制渲染的数据数量。

我的想法是这样的:任何时候都只渲染前100条数据以保证不卡顿,然后当需要搜索的时候对从后台拿到的数据进行过滤,也只取前100条,然后当select框不下拉的时候也就是失焦的时候将数据回复原样。

下面是我的具体实现:

先从后台拿到数据,保存到变量fundList中(作为数据源,永远不改动),然后取其中的前100条数据保存到fundList_中,用来下拉框的数据渲染

{fundList_.map(item => <Option key={item.fund} value={item.fund}>{item.name}</Option>)}

这是整个select组件:

<Select
 mode="multiple"
 maxTagCount={0}
 placeholder="请选择"
 showSearch={true}
 onBlur={this.handleOnBlur}
 onSearch={this.handleOnSearch}
 allowClear={true}
 onChange={(value)=>{this.modalChangeSelect(value,'1')}}
 style={{width:'223px'}}
 value={record['1']||undefined}
 disabled={this.state.visibleType==='修改'?true:false}
>
 {fundList_.map(item => <Option key={item.fund} value={item.fund}>{item.name}</Option>)}
</Select>

然后写search里面的功能

handleOnSearch = value => {
 // 函数节流,防止数据频繁更新,每300毫秒才搜索一次
 let that = this
 if (!this.timer) {
  this.timer = setTimeout(function(){
  that.searchValue(value)
  that.timer = null
  },300)
 }
 }
searchValue = (value) => {
 const datas = [] 
 const {fundList} = this.state
 // 对fundList进行遍历,将符合搜索条件的数据放入datas中
 fundList.forEach(item => {
 if (item.name.indexOf(value) > -1) {
  datas.push(item)
 }
 })
 // 然后只显示符合搜索条件的所有数据中的前100条
 this.setState({fundList_: datas.slice(0,100)})
}

当select失焦的时候,将数据恢复原样(只显示fundList中的前100条数据):

handleOnBlur = () => {
 this.setState({fundList_: this.state.fundList.slice(0,100)})
 }

到此这个功能就大体实现了,已经不存在卡顿的问题了,但是这个方法并不是完美的,这不,业务就说了,你只显示了前100条数据,但是我有时候不通过搜索功能查找某条数据,我要在所有的数据里面直接找到那条数据(业务也不嫌累。。。),我要显示所有的数据。

这下就难办了,因为卡顿就是渲染太多的数据造成的,所以还是不能一次性渲染所有的数据,然后怎么办呢,我也不知道怎么办呐。于是上网搜索了一下别人碰到相关问题的解决办法,于是还真的找到了。

思路是这样的:

同样是先只展示前100条数据(这个没办法,想要不卡只能这样),然后当滚动条滚到第100条数据也就是滚到底部的时候再增加100条,就这样一直到展示所有的数据,下面是具体的实现步骤:

1、先造点假数据:

const data = [];
for (let i = 0; i < 1000; i++) {
 data.push(`test${i}`);
}
// 一开始只展示前100条数据
const data_ = data.slice(0, 100);

2、渲染出来

<Select
 showSearch
 allowClear
 onPopupScroll={this.handleScroll}
 style={{ width: 200 }}
 placeholder="Select a person"
 optionFilterProp="children"
 onChange={this.onChange}
 onFocus={this.onFocus}
 onBlur={this.onBlur}
 onSearch={this.onSearch}
 filterOption={(input, option) =>
 option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
 }
>
 {optionData.map(item => (
 <Option value={item}>{item}</Option>
 ))}
</Select>

3、写滚动条滚动的功能

在这里就要说一下select里面的一个参数了,就是 onPopupScroll,以前没有注意到,看到别人提醒的时候才发现。有了它就可以实现滚动实时刷新数据了。

antd的select下拉框因为数据量太大造成卡顿的解决方式

然后写滚动的功能

handleScroll = e => {
 e.persist();
 const { target } = e;
 // scrollHeight:代表包括当前不可见部分的元素的高度
 // scrollTop:代表当有滚动条时滚动条向下滚动的距离,也就是元素顶部被遮住的高度
 // clientHeight:包括padding但不包括border、水平滚动条、margin的元素的高度
 const rmHeight = target.scrollHeight - target.scrollTop;
 const clHeight = target.clientHeight;
 // 当下拉框失焦的时候,也就是不下拉的时候
 if (rmHeight === 0 && clHeight === 0) {
  this.setState({ scrollPage: 1 });
 } else {
 // 当下拉框下拉并且滚动条到达底部的时候
 // 可以看成是分页,当滚动到底部的时候就翻到下一页
  if (rmHeight < clHeight + 5) {
  const { scrollPage } = this.state;
  this.setState({ scrollPage: scrollPage + 1 });
  //调用处理数据的函数增加下一页的数据
  this.loadOption(scrollPage + 1);
  }
 }
 };
 loadOption = pageIndex => {
 const { pageSize, keyWords } = this.state;
 // 通过每页的数据条数和页数得到总的需要展示的数据条数
 const newPageSize = pageSize * (pageIndex || 1);
 let newOptionsData = [],len; // len 能展示的数据的最大条数
 if (data.length > newPageSize) {
  // 如果总数据的条数大于需要展示的数据
  len = newPageSize;
 } else {
  // 否则
  len = data.length;
 }
 // 如果有搜索的话,就走这里
 if (!!keyWords) {
  let data_ = data.filter(item => item.indexOf(keyWords) > -1) || [];
  data_.forEach((item, index) => {
  if (index < len) {
   newOptionsData.push(item);
  }
  });
 } else {
  data.forEach((item, index) => {
  if (index < len) {
   newOptionsData.push(item);
  }
  });
 }
 this.setState({ optionData: newOptionsData });
 };

4、搜索功能:

和我刚开始的一样

onSearch = val => {
 console.log("search:", val);
 if (!this.timer) {
  const that = this;
  this.timer = setTimeout(function() {
  that.searchValue(val);
  that.timer = null;
  }, 300);
 }
 this.setState({ keyWords: val });
 };
 searchValue = value => {
 let data_ = data.filter(item => item.indexOf(value) > -1);
 if (data_.length > 100 || value === "") {
  data_ = data_.slice(0, 100);
 }
 this.setState({ optionData: data_ });
 };

5、 然后失焦的时候:

handleOnBlur = () => {
 this.setState({fundList_: this.state.fundList.slice(0,100)})
 }

总的代码:

import React from "react";
import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import "./index.css";
import { Select } from "antd";

const { Option } = Select;

const data = [];
// let pageSize = 100,scrollPage = 1,keyWords = '',optionData = [];
for (let i = 0; i < 1000; i++) {
 data.push(`test${i}`);
}

const data_ = data.slice(0, 100);

class App extends React.Component {
 state = {
 pageSize: 100,
 scrollPage: 1,
 keyWords: "",
 optionData: data_
 };

 onChange = value => {
 console.log(`selected ${value}`);
 };

 onBlur = () => {
 console.log("blur");
 this.setState({ optionData: data_ });
 };

 onFocus = () => {
 console.log("focus");
 };

 onSearch = val => {
 console.log("search:", val);
 if (!this.timer) {
  const that = this;
  this.timer = setTimeout(function() {
  that.searchValue(val);
  that.timer = null;
  }, 300);
 }
 this.setState({ keyWords: val });
 };
 searchValue = value => {
 let data_ = data.filter(item => item.indexOf(value) > -1);
 if (data_.length > 100 || value === "") {
  data_ = data_.slice(0, 100);
 }
 this.setState({ optionData: data_ });
 };
 loadOption = pageIndex => {
 const { pageSize, keyWords } = this.state;
 const newPageSize = pageSize * (pageIndex || 1);
 let newOptionsData = [],
  len;
 if (data.length > newPageSize) {
  len = newPageSize;
 } else {
  len = data.length;
 }
 if (!!keyWords) {
  let data_ = data.filter(item => item.indexOf(keyWords) > -1) || [];
  data_.forEach((item, index) => {
  if (index < len) {
   newOptionsData.push(item);
  }
  });
 } else {
  data.forEach((item, index) => {
  if (index < len) {
   newOptionsData.push(item);
  }
  });
 }
 this.setState({ optionData: newOptionsData });
 };

 handleScroll = e => {
 e.persist();
 const { target } = e;
 const rmHeight = target.scrollHeight - target.scrollTop;
 const clHeight = target.clientHeight;
 if (rmHeight === 0 && clHeight === 0) {
  this.setState({ scrollPage: 1 });
 } else {
  if (rmHeight < clHeight + 5) {
  console.log(111, rmHeight, clHeight);
  const { scrollPage } = this.state;
  this.setState({ scrollPage: scrollPage + 1 });
  // scrollPage = scrollPage + 1;
  this.loadOption(scrollPage + 1);
  }
 }
 // console.log(e.target)
 };

 render() {
 const { optionData } = this.state;
 console.log(optionData.length);
 return (
  <Select
  showSearch
  allowClear
  onPopupScroll={this.handleScroll}
  style={{ width: 200 }}
  placeholder="Select a person"
  optionFilterProp="children"
  onChange={this.onChange}
  onFocus={this.onFocus}
  onBlur={this.onBlur}
  onSearch={this.onSearch}
  filterOption={(input, option) =>
   option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
  }
  >
  {optionData.map(item => (
   <Option value={item}>{item}</Option>
  ))}
  </Select>
 );
 }
}

ReactDOM.render(<App />, document.getElementById("container"));

其实两个方法各有优劣,第一种的话没有卡顿,但是展示的数据量对于有些人来说可能不太够,而第二种方法呢虽然下拉没有卡顿,但是当滚动了很多数据的时候滚动就会有点卡并且选择某条数据也会有点卡。所以看场景了。

补充知识:VUE element select 选项内容显示过长问题

我就废话不多说了,大家还是直接看代码吧~

<style>
 .el-select__tags-text {
 display: inline-block;
 max-width: 120px;
 overflow: hidden;
 text-overflow: ellipsis;
 white-space: nowrap;
 }
 .el-select .el-tag__close.el-icon-close {
 top: -7px;
 }
</style>

antd的select下拉框因为数据量太大造成卡顿的解决方式

以上这篇antd的select下拉框因为数据量太大造成卡顿的解决方式就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JQuery通过Ajax提交表单并返回结果
Jul 31 Javascript
JQuery中form验证出错信息的查看方法
Oct 08 Javascript
jquery序列化表单去除指定元素示例代码
Apr 10 Javascript
jQuery实现首页顶部可伸缩广告特效代码
Apr 15 Javascript
javascript实现类似百度分享功能的方法
Jul 27 Javascript
JS使用post提交的两种方式
Dec 03 Javascript
jquery根据一个值来选中select下的option实例代码
Aug 29 Javascript
javascript代码优化的8点总结
Jan 29 Javascript
详解Puppeteer 入门教程
May 09 Javascript
详解如何用VUE写一个多用模态框组件模版
Sep 27 Javascript
Vue.js下拉菜单组件使用方法详解
Oct 19 Javascript
原生javascript运动函数的封装示例【匀速、抛物线、多属性的运动等】
Feb 23 Javascript
antd design table更改某行数据的样式操作
Oct 31 #Javascript
antd配置config-overrides.js文件的操作
Oct 31 #Javascript
解决ant-design-vue中menu菜单无法默认展开的问题
Oct 31 #Javascript
Ant Design的可编辑Tree的实现操作
Oct 31 #Javascript
antd多选下拉框一行展示的实现方式
Oct 31 #Javascript
解决antd 下拉框 input [defaultValue] 的值的问题
Oct 31 #Javascript
Vue使用CDN引用项目组件,减少项目体积的步骤
Oct 30 #Javascript
You might like
PHP开发中AJAX技术的简单应用
2015/12/11 PHP
PHP+Mysql无刷新问答评论系统(源码)
2016/12/20 PHP
php基于环形链表解决约瑟夫环问题示例
2017/11/07 PHP
php中try catch捕获异常实例详解
2020/08/06 PHP
使用jquery自定义鼠标样式满足个性需求
2013/11/05 Javascript
jQuery 追加元素的方法如append、prepend、before
2014/01/16 Javascript
javascript实现倒计时跳转页面
2016/01/17 Javascript
js轮播图代码分享
2016/07/14 Javascript
详解Nodejs之静态资源处理
2017/06/05 NodeJs
基于vue-cli vue-router搭建底部导航栏移动前端项目
2018/02/28 Javascript
vue 每次渲染完页面后div的滚动条保持在最底部的方法
2018/03/17 Javascript
微信小程序http连接访问解决方案的示例
2018/11/05 Javascript
vue-router懒加载速度缓慢问题及解决方法
2018/11/25 Javascript
vuedraggable+element ui实现页面控件拖拽排序效果
2020/07/29 Javascript
JS+php后台实现文件上传功能详解
2019/03/02 Javascript
JS代码简洁方式之函数方法详解
2020/07/28 Javascript
vue项目中企业微信使用js-sdk时config和agentConfig配置方式详解
2020/12/15 Vue.js
使用python实现tcp自动重连
2017/07/02 Python
对pandas里的loc并列条件索引的实例讲解
2018/11/15 Python
对python中Librosa的mfcc步骤详解
2019/01/09 Python
Python matplotlib绘制饼状图功能示例
2019/09/10 Python
Python3常见函数range()用法详解
2019/12/30 Python
Python基于Tensor FLow的图像处理操作详解
2020/01/15 Python
如何在pycharm中安装第三方包
2020/10/27 Python
Dockers美国官方网站:卡其裤、男士服装、鞋及配件
2016/11/22 全球购物
全球最大的游戏市场:G2A
2018/07/05 全球购物
CHARLES & KEITH台湾官网:新加坡时尚品牌
2019/07/30 全球购物
Armor Lux法国官方网站:水手服装、成衣和内衣
2020/05/26 全球购物
法定代表人授权委托书格式
2014/10/14 职场文书
党员反对四风思想汇报范文
2014/10/25 职场文书
车间安全生产管理制度
2015/08/06 职场文书
2016高一新生军训心得体会
2016/01/11 职场文书
十一月早安语录:把心放轻,人生就是一朵自在的云
2019/11/04 职场文书
SpringBoot整合RabbitMQ的5种模式实战
2021/08/02 Java/Android
SQL SERVER中的流程控制语句
2022/05/25 SQL Server
Apache POI操作批量导入MySQL数据库
2022/06/21 Servers