el-tree懒加载遇到的问题 —— 默认选中前几个节点,父节点以及所有子节点也被选中

针对el-tree组件在大量数据下的懒加载问题,本文提出了一种优化方案,通过自定义加载和处理子节点的方式,有效解决了父节点及子节点选中状态混乱的问题。

前言:el-tree使用懒加载方式(由于数据量大)设置默认选中的是父节点的前两个子节点,展开时,发现父节点和所有子节点全选中了,于是打了一下debugger,发现点击展开时,默认走选中的前两个子节点,到第二个节点是时走了reInitChecked方法,父节点的checked属性变成了true,因为父节点变成了true,所以他又将所有子节点都变成了true(莫名其妙子节点还没渲染完就重置了父节点的状态);然后我尝试了一下默认选中父节点的第一个和第三个节点,发现没有问题呢!???

首先我是使用懒加载的方式加载:简单写了个demo

createSignalLoadNodes (node, resolve) {
  let that = this
  let organId = node.data && node.data.organId ? node.data.organId : ""
  this.organService.getOrganChildren(organId, function (res) {
    if (res) {
      let cloneTreeData = that.convertTreeData(res)
      let time = arr.length + 200
      //这个方法重置节点状态
      this.setChildNodeChecked(node, time)
      resolve(cloneTreeData)
    }
  })
}

使用setChildNodeChecked方法重置节点选中状态

setChildNodeChecked (node, time) {
  setTimeout(() => {
    node.childNodes && node.childNodes.forEach(cell => {
      if (! this.defaultCheckedKeys.find(val => val == cell.data.id)) {
        cell.checked = false
        //本来想的是如果子节点有不选中的就给父节点添加半选
        // node.indeterminate = true
      } else {
        cell.checked = cell.checked
      }
      //重置半选
      this.addSelectChecked()
    });
  }, time)
}

发现子节点的状态对了,但是父节点还是勾选状态,于是在给子节点false的时候给父节点添加半选发现不起作用于是新写了一个方法addSelectChecked

addSelectChecked () {
  let tree: any = this.$refs.signalTree
  this.$nextTick(() =>{
    if (tree) {
      this.halfCheckedIds.forEach(item => {
        if (! this.defaultCheckedKeys.find(_m => _m == item)) {
          this.getNode(item).indeterminate = true
        }
      })
    }
  })
}

发现问题解决了,但是后来又发现了一个问题!!!

当父节点底下有几万个子节点时,发现不生效了,原因是啥呢重置子节点状态的方法(setChildNodeChecked )时,异步加载子节点不知道多长时间,而且就算把时间放长,等待到怀疑人生你的父节点的状态才有勾选变为半选

于是我在el-tree的node.js中找到doCreateChildren方法,当子节点大于2000条时设置checkStrictly等于true(父子节点不强制关联,当然父节点的选中状态是我手动判断),当数据加载完时将checkStrictly设置成false

当数据少于2000条时,上面的重置的方法够用我就没改了,就直接将checkStrictly设置成false

doCreateChildren方法是我进行处理过的,当一个节点的子节点数据大于2000条时,异步处理:https://blog.youkuaiyun.com/monparadis/article/details/114025100

doCreateChildren(array, defaultProps = {}) {
  const store = this.store
  if (array && array.length > 2000) {
    let arr = [...array]
    let num = 0 
    store.checkStrictly = true
    let handler = setInterval (() => {
      for (let i = 0; i < 500; i++) {
        if (num < arr.length) {
          this.insertChild(objectAssign({ data: arr[num] }, defaultProps), undefined, true)
          num ++
        }
        if (num === arr.length) {
          clearInterval(handler)
          store.checkStrictly = false
        }
      }
    })
  } else {
    store.checkStrictly = false
    array.forEach((item) => {
      this.insertChild(objectAssign({ data: item }, defaultProps), undefined, true)
    })
  }
}

当然这还有个问题当你树节点取消勾选进行操作时,记得把checkStrictly设置成false

到这里问题就解决了。

<think>嗯,用户问的是关于el-tree懒加载某个节点默认选中问题。首先,我需要回忆一下Element UI中的el-tree组件,特别是懒加载默认选中的处理方式。 用户可能是在使用Vue.js和Element UI开发一个需要动态加载子节点的树形结构,并且希望某个节点在初始化时就被选中。这时候,我需要考虑几个方面:懒加载的实现机制、节点选中的条件以及如何在数据异步加载后确保节点正确选中。 首先,el-tree懒加载是通过load属性指定的函数来实现的,这个函数在展开节点时触发。但是默认选中可能发生在节点加载之,比如节点数据还未获取,这时候直接设置selectedKey可能无法找到对应节点,导致选中失败。 接下来,默认选中通常是用default-selected-key或者通过设置节点selected属性。不过,在懒加载的情况下,如果节点未被加载,这些方法可能不奏效。这时候可能需要结合节点加载后的回调,或者手动触发加载直到目标节点被加载出来,然后再设置选中状态。 然后,考虑用户可能的场景。比如,用户可能从后端获取了一个节点的ID,需要在树初始化时展开并选中节点,但这个节点父节点可能还没加载,需要逐层加载父节点,直到目标节点可用。这时候可能需要递归地加载父节点,再加载子节点,最后选中目标节点。 另外,需要用到el-tree的getNode方法,通过节点的key来获取对应的Node对象。如果节点未加载,可能需要调用load方法强制加载,然后在load的回调中再次检查节点是否存在。 还要注意异步处理的问题,比如使用Promise或者async/await来确保节点加载完成后再进行选中操作。可能需要为loadNode函数添加回调参数,当数据加载完成后执行选中逻辑。 可能的步骤是: 1. 设置default-selected-key为目标节点的key。 2. 在load方法中,当加载完某个节点后,检查是否目标节点已经存在,如果存在则选中。 3. 如果目标节点在深层,可能需要逐层展开父节点,并触发它们的load方法,直到目标节点加载完毕。 需要注意的是,如果目标节点所在的父节点未展开,可能需要手动调用expand方法来展开父节点,从而触发懒加载。同时,处理异步加载的顺序,可能需要递归或链式调用load方法。 此外,用户可能遇到的问题是,即使调用了load方法,节点数据加载是异步的,直接调用setCurrentKey可能无法立即生效,因此需要在数据加载完成的回调中执行选中操作。 总结下来,解决方案可能包括:在mounted钩子中初始化时,递归加载父节点,直到目标节点加载完成,然后使用setCurrentKey方法选中节点。或者,在懒加载的load函数中,每次加载完成后检查是否为目标节点,如果是则选中。 最后,需要考虑代码示例的结构,展示如何结合load方法、default-selected-key和手动触发加载的逻辑,确保用户能够理解并应用到实际项目中。</think>在 Element UI 的 `el-tree` 组件中实现懒加载节点默认选中时,由于节点数据是异步加载的,直接设置 `default-selected-key` 可能无法生效(节点尚未加载)。以下是解决方案和示例: --- ### 核心思路 1. **递归触发懒加载**:从根节点开始逐层加载,直到目标节点被加载到树中。 2. **动态选中节点**:在目标节点加载完成后,通过 `setCurrentKey` 方法动态选中--- ### 代码示例 ```html <template> <el-tree ref="tree" :props="props" :load="loadNode" lazy @current-change="handleCurrentChange" ></el-tree> </template> <script> export default { data() { return { props: { label: 'name', children: 'children', isLeaf: 'isLeaf' }, targetKey: 3 // 假设要默认选中节点 key }; }, mounted() { // 初始化时尝试选中节点 this.trySelectNode(); }, methods: { // 递归加载节点直到目标节点存在 async trySelectNode() { const tree = this.$refs.tree; let node = tree.getNode(this.targetKey); if (!node) { // 如果节点未加载,从根节点开始递归加载 await this.loadParentNodes(tree.root, this.targetKey); node = tree.getNode(this.targetKey); } if (node) { tree.setCurrentKey(this.targetKey); } }, // 递归加载父节点路径 async loadParentNodes(node, targetKey) { // 假设你的节点结构可以推断父节点路径,这里需要根据实际数据结构调整 // 例如:假设 targetKey=3,父节点是2,祖父节点是1 const pathKeys = [1, 2, 3]; // 手动定义节点路径(实际应根据业务逻辑生成) for (const key of pathKeys) { const currentNode = node.childNodes.find(n => n.data.id === key); if (currentNode && !currentNode.loaded) { await new Promise(resolve => { currentNode.load(resolve); // 触发懒加载 }); } } }, // 懒加载方法 loadNode(node, resolve) { if (node.level === 0) { // 加载根节点 this.loadRootNodes(resolve); } else { // 加载子节点 this.loadChildNodes(node, resolve); } }, // 模拟加载根节点 loadRootNodes(resolve) { setTimeout(() => { resolve([ { id: 1, name: '父节点', isLeaf: false } ]); }, 500); }, // 模拟加载子节点 loadChildNodes(node, resolve) { setTimeout(() => { const parentId = node.data.id; const children = [ { id: parentId * 10 + 1, name: `子节点 ${parentId}-1`, isLeaf: parentId >= 2 }, { id: parentId * 10 + 2, name: `子节点 ${parentId}-2`, isLeaf: parentId >= 2 } ]; resolve(children); }, 500); } } }; </script> ``` --- ### 关键点解释 1. **递归加载路径**:通过 `loadParentNodes` 手动触发从根节点到目标节点的路径加载(需根据业务逻辑生成路径)。 2. **异步等待加载**:使用 `Promise` 确保节点加载完成后再继续后续操作。 3. **动态选中**:在确认节点存在后,使用 `setCurrentKey` 方法选中--- ### 注意事项 - **节点路径推断**:示例中的 `pathKeys` 是硬编码的,实际需要根据你的节点数据结构生成父节点路径。 - **性能优化**:深层节点递归加载可能影响性能,建议结合业务限制最大层级。 - **错误处理**:添加加载失败时的异常处理(如网络错误)。 如果需要更动态的路径推断,可以结合后端 API 获取节点的祖先路径。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值