温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

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

发布时间:2020-11-02 15:23:11 来源:亿速云 阅读:827 作者:Leah 栏目:开发技术

这篇文章将为大家详细讲解有关antd的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==='修改'&#63;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下拉框因为数据量太大造成卡顿如何解决就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI