Element实现穿梭框出现卡顿问题怎么优化,有哪些方案
Admin 2022-07-02 群英技术资讯 951 次浏览
懒加载的方式可以用EUI的无限滚动:https://element.eleme.cn/
即便我们做了懒加载之后,点击全选依旧是卡顿6秒以上,所以方案一解决的是:即便做了懒加载或者分页操作后,用户点击分页,依旧会卡顿几秒的情况。
这个是因为transfer的源码中‘全选判断'代码性能差的原因,方案一就是修改transfer的源码。
我提交了一个pr,地址是: hhttps://github.com/ElemeFE/element/pull/20282
EUI的transfer组件目录路径:node_modules\element-ui\packages\transfer,复制文件夹,然后放入vue项目路径的
在调用EUI的transfer的地方引入公共的组件transfer,
<template> <Transfer v-model="value" :data="data"></Transfer> </template> <script> import Transfer from '../common/transfer' export default { components:{ Transfer:Transfer }, //省略 </script>
开始修改transfer代码:
打开src/common\transfer\src\transfer-panel.vue的组件,
找到updateAllChecked函数,updateAllChecked函数作用是:我们点击一个item就需要判断,看代码注释。
updateAllChecked() { /* 源码 this.checkableData是对象数组 我们需要的是每个对象中的key 所以checkableDataKeys保存着对象的key的数组 含义是'可通过点击进行选择的item项'的集合 */ let start = new Date().getTime(); const checkableDataKeys = this.checkableData.map( item => item[this.keyProp] ); this.allChecked = checkableDataKeys.length > 0 && /* 从2.4.0到现在都没改变 诶,不得不说开发团队是真的忙啊 this.checked保存着'用户通过点击item选中的item数组' 如果this.checked存在着checkableDataKeys的每一项的话,那么allChecked就是true,但凡有一项不存在就为false。allChecked代表是否全部选中了。 这里的时间复杂度是n^2,狠垃圾 */ checkableDataKeys.every(item => this.checked.indexOf(item) > -1); console.log("updateAllCheckedEnd", new Date().getTime() - start); },
来看源码的耗时:
然后我们开始重写updateAllChecked函数:
updateAllChecked() { /* 修改 这里就是高效数组中含有另一个数组的元素的算法 构建元素对象 */ let start = new Date().getTime(); let checkableDataKeys = this.checkableData.map((item) => { let keyProps = {}; keyProps[item[this.keyProp]] = true; return keyProps; }); // 通过对象的k-v对应,n(1)的方式寻找数组中是否存在某元素 this.allChecked = checkableDataKeys.length > 0 && this.checked.length > 0 && this.checked.every((item) => checkableDataKeys[item]); // 上面被注释的源码是最耗时的,所有一直看耗时就可以了 console.log("updateAllCheckedEnd", new Date().getTime() - start); },
这样性能就高好多了,其实就是基本的前端算法题,目测EUI的开发者是因为懒才不写的。
来看修改代码后的耗时:
明显快多了。
接下来是文件:\src\common\transfer\src\main.vue,找到addToRight函数
addToRight() { let currentValue = this.value.slice(); const itemsToBeMoved = []; const key = this.props.key; let start = new Date().getTime(); // 此处套了两层循环,耗时长 this.data.forEach((item) => { const itemKey = item[key]; if ( this.leftChecked.indexOf(itemKey) > -1 && this.value.indexOf(itemKey) === -1 ) { itemsToBeMoved.push(itemKey); } }); console.log("addToRightEnd", new Date().getTime() - start); currentValue = this.targetOrder === "unshift" ? itemsToBeMoved.concat(currentValue) : currentValue.concat(itemsToBeMoved); this.$emit("input", currentValue); this.$emit("change", currentValue, "right", this.leftChecked); },
移动选中的耗时:
修改addToRight函数,
addToRight() { let start = new Date().getTime(); let currentValue = this.value.slice(); const itemsToBeMoved = []; const key = this.props.key; // 修改 let leftCheckedKeyPropsObj = {}; this.leftChecked.forEach((item, index) => { leftCheckedKeyPropsObj[item] = true; }); let valueKeyPropsObj = {}; this.value.forEach((item, index) => { valueKeyPropsObj[item] = true; }); this.data.forEach((item) => { const itemKey = item[key]; if ( leftCheckedKeyPropsObj[itemKey] && !valueKeyPropsObj[itemKey] ) { itemsToBeMoved.push(itemKey); } }); console.log("addToRightEnd", new Date().getTime() - start); currentValue = this.targetOrder === "unshift" ? itemsToBeMoved.concat(currentValue) : currentValue.concat(itemsToBeMoved); this.$emit("input", currentValue); this.$emit("change", currentValue, "right", this.leftChecked); },
移动选中耗时:
耗时明显减少了,这方案的前提就是懒加载或者分页,我试了一下10w的数据量,依旧是不错的。
checkBox-group有个check数组(用来记录已经选中的item数组)和renderItem数组(实际渲染的item,由于是分页,所有不会渲染所有),如果`check数组`中有`renderItem数组`的一项,那么该项就会被标记为已选,否则是未选。实现原理就是单纯的check数组和renderItem数组进行比较。
当用户点击全选的时候,check数组变成上万条数据的数组,此时我们渲染了100条数据,那么就要进行10000x100级别的循环,这就是耗时的原因所在。
其实,页面只渲染了100条数据,我们没必要将上万条数据一次性放入check数组中,我们只需要把这100条数组放入check数组,显示这100条数据为已选即可。当页面渲染了更多数据的同时,将新增的数据添加进check数组即可。这样性能大大提升。
我采用的方案如下:
1.只显示100条数据。
2.下拉显示下100条数据,上拉显示上100条数据。
3.当下拉或者上拉增加渲染数据的同时,把新增数据添加进check数组。
这些只是大致思路,我已经实现了。还有很多细节要处理,想要完善,还得利用对象的键值对实现删除等。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
这篇文章要实现的需求是打开其他项目并传数据的的内容,那么vue如何向其他项目页面传数据?下面给大家介绍不跨域和跨域这两种情况下的方法,感兴趣的朋友接下来跟随小编来参考一下吧。
jquery.md5有什么用jQuery md5加密插件jQuery.md5.js用法有时候我们想在js里面使用加密,jQuery就提供了这样的插件,用法十分简单使用方法:<div class="jb51code">rush:Js;">$.(
javascript如何实现继承?有哪些继承方法?很多刚接触javascrip继承的朋友,可能对于javascrip继承方法不是很清楚,因此这篇文章文章就给大家介绍一下JavaScript 实现继承的几种方式,小编认为是比较实用的,下面就跟随小编一起来了解一下吧。
vue3 沙箱主要分两种,浏览器编译版本,浏览器版本是使用with语法加上proxy代理拦截;本地预编译版本,通过在模版预编译阶段转换阶段,使用转换插件transformExpression将非白名单标识符挂在在组件代理对象下
这篇文章我们来了解JavaScript怎样删除set中的元素,这里给大家分享两个方法,分别是delete()方法和clear(),那么它们有何不同呢?实现代码怎样写?下文有很详细的介绍,有需要的朋友可以参考,接下来就跟随小编来一起学习一下吧!
成为群英会员,开启智能安全云计算之旅
立即注册Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008