当展示超大量数据时,我们可以使用elementui 提供的虚拟化树形控件。但是我遇到一个问题,当我想去默认展开大量节点的时候,界面还是会卡死一段时间。
我开始直接使用了setCheckedKeys方法,一下子传入了3000个key,界面通常会卡一秒钟。于是我想到了requestAnimationFrame来将操作分片的方法。
requestAnimationFrame 是一个在浏览器中用于执行动画和进行其他需要同步更新的操作的 JavaScript
方法。它被设计用来利用浏览器的刷新频率进行优化,以避免过多地占用 CPU 资源,并且能够在下一次浏览器
绘制之前执行代码。
也就是我可以先将要加在的数据进行分组,然后在requestAnimationFrame的回调中依次将节点做一个勾选(这样可以在渲染间歇中执行我们的js代码,页面不会有明显的卡顿),直到所有的都勾选完成。
以下是可以参考的代码:
const setCheckedNode = function (nodeKeys) {
// this -> thisTreeData
if (!nodeKeys.length) {
this.treeRef.setCheckedKeys([]);
return this.treeRef.setExpandedKeys([]);
}
function setRender(fn, dataArr) {
const _this = this;
let lastFrame = 0;
let curGroup = 0;
let groupData = [[]];
let _id = null;
// 将长数组分组,我这里分的是100个一组
for (const dataArrElement of dataArr) {
let lastGroupItem = groupData[groupData.length - 1];
if (lastGroupItem.length === 100) {
groupData.push([]);
lastGroupItem = groupData[groupData.length - 1];
}
lastGroupItem.push(dataArrElement);
}
// 递归去执行传进来的fn(即设置checkedKeys方法)
function run() {
_id = requestAnimationFrame((frame) => {
if (lastFrame === 0 || frame - lastFrame > 30) {
lastFrame = frame;
fn.apply(this, [groupData[curGroup]]);
if (curGroup >= groupData.length - 1) {
// 递归的退出条件,全部加载完成
cancelAnimationFrame(_id);
_id = null;
_this.loading = false;
return;
}
curGroup += 1;
}
run();
});
}
run();
}
setRender.apply(this, [(renderKeys) => {
// 这里使用了通过props传defaultKeys的方法,因为setCheckedKeys会将上次设置的节点状态
// 改为false
defaultChecked.value = renderKeys;
}, nodeKeys]);
}