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 相关文章推荐
判断JavaScript对象是否可用的最正确方法分析
Oct 03 Javascript
js实现局部页面打印预览原理及示例代码
Jul 03 Javascript
js判断手机浏览器操作系统和微信浏览器的方法
Apr 30 Javascript
d3.js中冷门却实用的内置函数总结
Feb 04 Javascript
将angular-ui的分页组件封装成指令的方法详解
May 10 Javascript
js 中rewrap-ajax.js插件实例代码
Oct 20 Javascript
JQuery属性操作与循环用法示例
May 15 jQuery
javascript实现日历效果
Jun 17 Javascript
微信小程序本地存储实现每日签到、连续签到功能
Oct 09 Javascript
vue实现吸顶、锚点和滚动高亮按钮效果
Oct 21 Javascript
jquery实现掷骰子小游戏
Oct 24 jQuery
vue实现短信验证码登录功能(流程详解)
Dec 10 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
在yii中新增一个用户验证的方法详解
2013/06/20 PHP
php中OR与|| AND与&amp;&amp;的区别总结
2013/10/26 PHP
php采用file_get_contents代替使用curl实例
2014/11/07 PHP
Zend Framework教程之配置文件application.ini解析
2016/03/10 PHP
基于ThinkPHP5.0实现图片上传插件
2017/09/25 PHP
PHP安装BCMath扩展的方法
2019/02/13 PHP
PHP7引入的&quot;??&quot;和&quot;?:&quot;的区别讲解
2019/04/08 PHP
php实现的数组转xml案例分析
2019/09/28 PHP
JS BASE64编码 window.atob(), window.btoa()
2021/03/09 Javascript
MooTools 1.2介绍
2009/09/14 Javascript
JS 控制非法字符的输入代码
2009/12/04 Javascript
用js模拟JQuery的show与hide动画函数代码
2010/09/20 Javascript
关于jquery.validate1.9.0前台验证的使用介绍
2013/04/26 Javascript
jQuery删除节点的三个方法即remove()detach()和empty()
2013/12/27 Javascript
删除javascript中注释语句的正则表达式
2014/06/11 Javascript
node.js中的emitter.emit方法使用说明
2014/12/10 Javascript
JavaScript学习心得之概述
2015/01/20 Javascript
JS实现常见的TAB、弹出层效果(TAB标签,斑马线,遮罩层等)
2015/10/08 Javascript
给before和after伪元素设置js效果的方法
2015/12/04 Javascript
Ubuntu 16.04 64位中搭建Node.js开发环境教程
2016/10/19 Javascript
微信小程序 实现列表项滑动显示删除按钮的功能
2017/04/13 Javascript
图片加载完成再执行事件的实例
2017/11/16 Javascript
BootStrap自定义popover,点击区域隐藏功能的实现
2018/01/23 Javascript
node命令行工具之实现项目工程自动初始化的标准流程
2019/08/12 Javascript
解决vue项目运行npm run serve报错的问题
2020/10/26 Javascript
js实现鼠标拖曳效果
2020/12/30 Javascript
Python机器学习之K-Means聚类实现详解
2018/02/22 Python
Python获取航线信息并且制作成图的讲解
2019/01/03 Python
python 使用csv模块读写csv格式文件的示例
2020/12/02 Python
CSS3属性box-sizing使用指南
2014/12/09 HTML / CSS
input元素的url类型和email类型简介
2012/07/11 HTML / CSS
荷兰手表网站:Watch2Day
2018/07/02 全球购物
专升本自我鉴定
2013/10/10 职场文书
国贸专业个人求职信范文
2014/01/08 职场文书
分布式架构Redis中有哪些数据结构及底层实现原理
2022/03/13 Redis
Vue操作Storage本地化存储
2022/04/29 Vue.js