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 实现的全选和反选
Apr 15 Javascript
JQuery 操作select标签实现代码
May 14 Javascript
jquery jqPlot API 中文使用教程(非常强大的图表工具)
Aug 15 Javascript
设置checkbox为只读(readOnly)的两种方式
Oct 11 Javascript
vue快捷键与基础指令详解
Jun 01 Javascript
js实现从左向右滑动式轮播图效果
Jul 07 Javascript
vue init失败简单解决方法(终极版)
Dec 22 Javascript
关于js的三种使用方式(行内js、内部js、外部js)的程序代码
May 05 Javascript
vue-router动态设置页面title的实例讲解
Aug 30 Javascript
js实现圆形显示鼠标单击位置
Feb 11 Javascript
解决父组件将子组件作为弹窗调用只执行一次created的问题
Jul 24 Javascript
基于JavaScript实现省市联动效果
Jun 22 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 文件系统详解
2012/09/13 PHP
解析php中heredoc的使用方法
2013/06/17 PHP
PHP操作MySQL的mysql_fetch_* 函数的常见用法教程
2015/12/25 PHP
laravel手动创建数组分页的实现代码
2018/06/07 PHP
JS 继承实例分析
2008/11/04 Javascript
Javascript实现的鼠标经过时播放声音
2010/05/18 Javascript
DD_belatedPNG,IE6下PNG透明解决方案(国外)
2010/12/06 Javascript
基于jquery的大众点评,分类导航实现代码
2011/08/23 Javascript
ASP.NET jQuery 实例11 通过使用jQuery validation插件简单实现用户登录页面验证功能
2012/02/03 Javascript
Underscore.js 的模板功能介绍与应用
2012/12/24 Javascript
Javascript 函数parseInt()转换时出现bug问题
2014/05/20 Javascript
Three.js快速入门教程
2016/09/09 Javascript
原生js实现放大镜效果
2017/01/11 Javascript
vue中的provide/inject的学习使用
2018/05/09 Javascript
create-react-app修改为多页面支持的方法
2018/05/17 Javascript
微信小程序首页的分类功能和搜索功能的实现思路及代码详解
2018/09/11 Javascript
vue实现的树形结构加多选框示例
2019/02/02 Javascript
ES6基础之默认参数值
2019/02/21 Javascript
nodejs使用socket5进行代理请求的实现
2020/02/21 NodeJs
js实现炫酷光感效果
2020/09/05 Javascript
vue使用vue-quill-editor富文本编辑器且将图片上传到服务器的功能
2021/01/13 Vue.js
python使用wxPython打开并播放wav文件的方法
2015/04/24 Python
Python中查看文件名和文件路径
2017/03/31 Python
基于python批量处理dat文件及科学计算方法详解
2018/05/08 Python
Python 打印中文字符的三种方法
2018/08/14 Python
对Python中内置异常层次结构详解
2018/10/18 Python
Python Series从0开始索引的方法
2018/11/06 Python
解决python ogr shp字段写入中文乱码的问题
2018/12/31 Python
Django网络框架之创建虚拟开发环境操作示例
2019/06/06 Python
浅谈Python中的模块
2020/06/10 Python
基于OpenCV的路面质量检测的实现
2020/11/04 Python
python实现学生信息管理系统(精简版)
2020/11/27 Python
英国排名第一的停车场运营商:NCP
2019/08/26 全球购物
学生检讨书怎么写
2014/10/09 职场文书
房地产置业顾问工作总结
2015/10/23 职场文书
《游戏王:大师决斗》新活动上线 若无符合卡组可免费租用
2022/04/13 其他游戏