element-ui el-tree大数据量取消勾选卡顿问题

前言

Element-UIel-tree 组件是一个非常常用的组件,它可以用来显示和处理树形结构数据。然而,当处理大数据量时,重置为未勾选状态的操作可能会导致页面卡顿,这是因为该操作要进行大量的循环,而这些循环有些是不需要的。

分析与解决方法

el-tree选中和取消勾选,会执行node.js文件下的setChecked函数。在setChecked函数内会递归节点,设置勾选状态。

Element-UI el-tree 源码文件路径:packeages\tree\src\model\node.js

函数执行逻辑如下:

graph TB Q(setChecked) --> P(调用 getChildState 设置节点状态) --> O{handleDescendants} --> A{depp} A{depp}-->|true| B(进入 for 循环递归) -.-> Q -.-> P -.-> F(reInitChecked 递归设置父级状态) -.-> P A{depp}-->|false| I(reInitChecked 递归设置父级状态)

知道了大概的逻辑,就可以打断点或者加console.log来分析代码。为了能更好的在文章中展示,本次使用console.log来分析代码。

使用三种不同的方法测试,重置勾选状态,包括在5000+数据的情况下需要耗时多久。

  1. 使用官方推荐的this.$refs.tree.setCheckedKeys([])方法,设置所有选中节点为未勾选状态;
js 复制代码
let nodes = this.$refs.tree.getCheckedNodes()  
nodes.map(item => { 
    this.$refs.tree.setChecked(item)  
})

一次性重置5000+条数据耗时:

  1. 使用getCheckedNodes()获取选中节点,然后再使用setChecked循环设置未勾选状态;

一次性重置5000+条数据耗时:

  1. 使用setChecked,只设置选中节点的父级为未勾选状态;
js 复制代码
this.$refs.tree.setChecked('4', false, true)

一次性重置5000+条数据耗时:

总结:

  • 测试1.全部节点循环了一遍,其中包括未勾选的节点;
  • 测试2.勾选了5个节点。取消勾选状态,循环调用getChildState函数9次,加上循环调用this.$refs.tree.setChecked的次数,总共循环了14次;
  • 测试3.只循环调用getChildState函数3次;

以上,只计算了getChildState函数调用次数,getChildState函数内还有for循环,如果在大数据量的情况下,这么多次的循环和递归必然会造成卡顿。

尽量使用测试3.的方法,只针对父级设置为未勾选状态

源码

html 复制代码
<template>
  <div>
    <button @click="reset">重置</button>
    <el-tree
        ref="tree"
        :data="data"
        @check="check"
        show-checkbox
        node-key="id"
        :default-expanded-keys="[]"
        :props="defaultProps">
    </el-tree>
  </div>
</template>

<script>
export default {
  data() {
    return {
      data: [{
        id: 1,
        label: '一级 1',
        children: [{
          id: 4,
          label: '二级 1-1',
          children: [{
            id: 9,
            label: '三级 1-1-1'
          }, {
            id: 10,
            label: '三级 1-1-2'
          }]
        }, {
          id: 99,
          label: 'asasa'
        },
          {
            id: 88,
            label: 'vcvcvc'
          }]
      }, {
        id: 2,
        label: '一级 2',
        children: [{
          id: 5,
          label: '二级 2-1'
        }, {
          id: 6,
          label: '二级 2-2'
        }]
      }, {
        id: 3,
        label: '一级 3',
        children: [{
          id: 7,
          label: '二级 3-1'
        }, {
          id: 8,
          label: '二级 3-2'
        }]
      }],
      defaultProps: {
        children: 'children',
        label: 'label'
      },
      setData: new Set()
    };
  },
  created() {
    for (let i = 0; i < 5000; i++) {
      this.data[0].children.push({
        id: i + 100,
        label: i
      })
    }
  },
  methods: {
    reset() {
      console.time('耗时')
      // this.$refs.tree.setCheckedKeys([])

      let arr = Array.from(this.setData)
      let node = null
      for (let item of arr) {
        node = this.$refs.tree.getNode(item)
        if (!node.checked && !node.indeterminate) continue
        this.$refs.tree.setChecked(item, false, true)
      }

      let nodes = this.$refs.tree.getCheckedNodes()
      console.log(nodes)
      // nodes.map(item => {
      //   this.$refs.tree.setChecked(item)
      // })

      console.timeEnd('耗时')
    },
    check(a) {
      let node = this.$refs.tree.getNode(a.id)
      this.setData.add(node.parent.key || node.key)
    }
  }
};
</script>

建议

Vue2项目,建议大数据量的树形结构数据,使用vue-easy-tree库,vue-easy-tree很好的实现了虚拟列表树。

vue-easy-tree使用el-tree二次开发,所以可以很好的支持el-tree的 API,可以很方便的替换原有的el-tree

相关推荐
灵犀学长4 分钟前
解锁HTML5页面生命周期API:前端开发的新视角
前端·html·html5
源码云商12 分钟前
基于 SpringBoot + Vue 的 IT 技术交流和分享平台的设计与实现
vue.js·spring boot·后端
江号软件分享13 分钟前
轻松解决Office版本冲突问题:卸载是关键
前端
致博软件F2BPM20 分钟前
Element Plus和Ant Design Vue深度对比分析与选型指南
前端·javascript·vue.js
慧一居士1 小时前
flex 布局完整功能介绍和示例演示
前端
DoraBigHead1 小时前
小哆啦解题记——两数失踪事件
前端·算法·面试
一斤代码7 小时前
vue3 下载图片(标签内容可转图)
前端·javascript·vue
中微子7 小时前
React Router 源码深度剖析解决面试中的深层次问题
前端·react.js
光影少年7 小时前
从前端转go开发的学习路线
前端·学习·golang
中微子7 小时前
React Router 面试指南:从基础到实战
前端·react.js·前端框架