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 相关文章推荐
一个无限级XML绑定跨框架菜单(For IE)
Jan 27 Javascript
服务端 VBScript 与 JScript 几个相同特性的写法 By shawl.qiu
Mar 06 Javascript
javascript fullscreen全屏实现代码
Apr 09 Javascript
关闭浏览器时提示onbeforeunload事件
Dec 25 Javascript
原生js实现类似弹窗抖动效果
Apr 02 Javascript
jQuery中常用的遍历函数用法实例总结
Sep 01 Javascript
JSON+Jquery省市区三级联动
Jan 13 Javascript
基于JavaScript实现单选框下拉菜单添加文件效果
Jun 26 Javascript
JavaScript 中有关数组对象的方法(详解)
Aug 15 Javascript
javaScript如何跳出多重循环break、continue
Sep 01 Javascript
Vue.js 2.0中select级联下拉框实例
Mar 06 Javascript
vue项目中axios使用详解
Feb 07 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
用mysql内存表来代替php session的类
2009/02/01 PHP
php中导出数据到excel时数字变为科学计数的解决方法
2013/02/03 PHP
在Yii框架中使用PHP模板引擎Twig的例子
2014/06/13 PHP
php封装的图片(缩略图)处理类完整实例
2016/10/19 PHP
php自定义扩展名获取函数示例
2016/12/12 PHP
Yii框架弹出窗口组件CJuiDialog用法分析
2017/01/07 PHP
php自定义截取中文字符串-utf8版
2017/02/27 PHP
PHP编程实现微信企业向用户付款的方法示例
2017/07/26 PHP
php 提交表单 关闭layer弹窗iframe的实例讲解
2018/08/20 PHP
PHP asXML()函数讲解
2019/02/03 PHP
javascript Firefox与IE 替换节点的方法
2010/02/24 Javascript
location.href语句与火狐不兼容的问题
2010/07/04 Javascript
jquery实现仿新浪微博评论滚动效果
2015/08/06 Javascript
浅谈JavaScript中小数和大整数的精度丢失
2016/05/31 Javascript
jQuery组件easyui对话框实现代码
2016/08/25 Javascript
Jquery 整理元素选取、常用方法一览表
2016/11/26 Javascript
理解javascript中的闭包
2017/01/11 Javascript
node前端开发模板引擎Jade的入门
2018/05/11 Javascript
使用node.js实现微信小程序实时聊天功能
2018/08/13 Javascript
扫微信小程序码实现网站登陆实现解析
2019/08/20 Javascript
使用scrapy实现爬网站例子和实现网络爬虫(蜘蛛)的步骤
2014/01/23 Python
解决Python2.7中IDLE启动没有反应的问题
2018/11/30 Python
Python分析彩票记录并预测中奖号码过程详解
2019/07/09 Python
tensorflow -gpu安装方法(不用自己装cuda,cdnn)
2020/01/20 Python
python3中布局背景颜色代码分析
2020/12/01 Python
布局和排版教程 纯css3实现图片三角形排列
2014/10/17 HTML / CSS
Html5之title吸顶功能
2018/06/04 HTML / CSS
商场消防管理制度
2014/01/12 职场文书
销售员个人求职的自我评价
2014/02/10 职场文书
班主任经验交流会主持词
2014/04/01 职场文书
实习单位意见
2015/06/04 职场文书
初中军训感言
2015/08/01 职场文书
公务员的复习计划书,请收下!
2019/07/15 职场文书
Django显示可视化图表的实践
2021/05/10 Python
Java后台生成图片的完整步骤
2021/08/04 Java/Android
使用Nginx搭载rtmp直播服务器的方法
2021/10/16 Servers