el-tree实现懒加载(调用接口获得每个节点的数据)

1,161 阅读3分钟

el-tree实现懒加载(调用接口获得每个节点的数据)

20241113更新说明:修复了一个bug(节点展开前就去勾选,导致有些地方没勾选上),此版本可直接到文章“20241113更新-优化逻辑、修复bug”处查看

添加el-tree元素

  • node-key="value"要添加,如果是可勾选的情况,没有添加的话无法获取已勾选的数据
  • :load="loadChildren"是每次点击某个节点时,会执行的函数,用于获取该节点下的数据
  • lazy 标识是懒加载
  • show-checkbox 标识可勾选
  • :props="treeProps" 定义了节点属性
  • ref="tree" 用于后续获取此元素以及已勾选的数据
<el-tree node-key="value" :load="loadChildren" lazy show-checkbox :props="treeProps" ref="tree"></el-tree>

写对应的函数

  • treeProps定义节点属性,可能会出现label: 'id'这种情况,因为获取到的数据可能和自己定义的名称不一致
  • 如果用v-if包裹el-tree,this.refs.tree会是undefined,需要使用this.refs.tree会是undefined,需要使用this.nextTick(()=>{})的方法
  • loadChildren函数,node包含了该节点的一些数据;自己定义的数据比如label在node.data;resolve函数主要是返回获取到的节点数据;reject我这里没用到
export default {
    data() {
        return {
            treeProps: {
                children: 'children',
                label: 'label',
                level: 'level',
                parentCategoryId: 'parentCategoryId',
                selected: 'selected',
                value: 'value',
              },
        }
    }
    methods: {
        getSelectedNodes() {
            this.$nextTick(() => {
                // 元素显示后执行
                const checkedNodes = this.$refs.tree.getCheckedNodes();
                console.log(checkedNodes, 'checkedNodescheckedNodescheckedNodes')
            })
        },
        loadChildren(node, resolve, reject) {
            // 如果是根节点,获取第一级的所有数据
            if (node.level === 0) {
                let tempData = []
                qygApi.categoryTree({
                  companyId: this.currentId,
                  level: node.level + 1,
                }).then(res => {
                  if (res.code == 'success') {

                    tempData = res.data
                  }

                })
                setTimeout(() => {
                  console.log(tempData, 'tempDatatempDatatempData');
                  resolve(tempData)
                }, 300);
            }
            // 如果不是根节点,获取点击节点的数据
            if (node.level >= 1) {
                let tempData = []
                qygApi.categoryTree({
                  companyId: this.currentId,
                  level: node.level + 1,
                  parentCategoryId: node.data.value,
                }).then(res => {
                  // this.nodeData = res.data
                  // console.log('this.nodeData', this.nodeData);
                  if (res.code == 'success') {

                    tempData = res.data
                  }

                })
                setTimeout(() => {
                  console.log(tempData, 'tempDatatempDatatempData');
                  resolve(tempData)
                }, 300);
          }



        },
    }
}

loadChildren函数更新了一些

  • 使用了async和await(最开始用的时候没有效果,所以用了setTimeout)
  • 如果调用接口失败或无数据,一般节点的下拉三角会消失,此节点变为叶子节点;如果要实现调用接口返回失败的情况下还能继续发起调用,可以更改节点状态node.loaded = false;node.loading = false;
async loadChildren(node, resolve, reject) {
      console.log(node, '如果是根节点,则直接提供数据如果是根节点,则直接提供数据');
      // this.getSelectedNodes()
      if (node.level === 0) {
        // this.categoryTreeData = 
        // console.log('this.categoryTreeData', this.categoryTreeData);
        // console.log('props.currentId', props.currentId);
        let tempData = []
        await qygApi.categoryTree({
          companyId: this.currentId,
          level: node.level + 1,
          // parentCategoryId: node.parentCategoryId,
        }).then(res => {
          // this.nodeData = res.data
          // console.log('this.nodeData', this.nodeData);
          if (res.code == 'success') {

            tempData = res.data
          }

        })


        // setTimeout(() => {
          console.log(tempData, 'tempDatatempDatatempData');
          resolve(tempData)
          if (!tempData) {
            reject()
          }
        // }, 1000);




      }
      if (node.level >= 1) {
        // const tempData = this.fetchChildrenNodeData(this.currentId, node.level + 1, node.value)
        console.log(node, 'nodenodenode');

        let tempData = []
        console.log('starttime', dayjs());

        await qygApi.categoryTree({
          companyId: this.currentId,
          level: node.level + 1,
          parentCategoryId: node.data.value,
        }).then(res => {
          // this.nodeData = res.data
          // console.log('this.nodeData', this.nodeData);
          if (res.code == 'success') {

            tempData = res.data
          }

        })
        console.log('endtime', dayjs());

        // setTimeout(() => {
          console.log(tempData, 'tempDatatempDatatempData');

          if (tempData.length == 0 && node.level == 3) {
            var self = this
            console.log('加载失败加载失败加载失败');
            
            self.$message.error('加载失败,请点击重新加载')
            node.loaded = false
            node.loading = false
            reject()
          } else {
            resolve(tempData)
          }
        // }, 10);
      }



    },

新增了回显

  • 首先是loadChildren函数加了this.loadSelectedData(this.tempData),调用loadSelectedData遍历selected属性0 不选 1全选 2半选
async loadChildren(node, resolve, reject) {
      console.log(node, '如果是根节点,则直接提供数据如果是根节点,则直接提供数据');
      // this.getSelectedNodes()
      if (node.level === 0) {
        this.defaultExpandedNodes = []

        // this.categoryTreeData = 
        // console.log('this.categoryTreeData', this.categoryTreeData);
        // console.log('props.currentId', props.currentId);
        this.tempData = []
        await qygApi.categoryTree({
          companyId: this.currentId,
          level: node.level + 1,
          // parentCategoryId: node.parentCategoryId,
        }).then(res => {
          // this.nodeData = res.data
          // console.log('this.nodeData', this.nodeData);
          if (res.code == 'success') {

            this.tempData = res.data
          }

        })


        // setTimeout(() => {
        console.log(this.tempData, 'tempDatatempDatatempData');
        resolve(this.tempData)
        // this.loadChildren(this.$refs.tree.getNode('11'), resolve, reject)


        if (!this.tempData) {
          reject()
        }
        // }, 1000);
        this.shouldCheckedKeys = []
        this.loadSelectedData(this.tempData)


      }
      if (node.level >= 1) {
        // const tempData = this.fetchChildrenNodeData(this.currentId, node.level + 1, node.value)
        console.log(node, 'nodenodenode');

        this.tempData = []
        console.log('starttime', dayjs());

        await qygApi.categoryTree({
          companyId: this.currentId,
          level: node.level + 1,
          parentCategoryId: node.data.value,
        }).then(res => {
          // this.nodeData = res.data
          // console.log('this.nodeData', this.nodeData);
          if (res.code == 'success') {

            this.tempData = res.data
          }

        })
        console.log('endtime', dayjs());

        // setTimeout(() => {
        console.log(this.tempData, 'tempDatatempDatatempDataaaaa');

        if (this.tempData.length == 0 && node.level == 3) {
          var self = this
          console.log('加载失败加载失败加载失败');

          self.$message.error('加载失败,请点击重新加载')
          node.loaded = false
          node.loading = false
          reject()
        } else {
          resolve(this.tempData)
          // this.tempData.forEach(item => {

          //   // 0 不选 1全选 2半选
          //   if (item.selected == 1) {
          //     this.addSelectedNodes([item.value]);
          //   } else if (item.selected == 2) {
          //     // this.addSelectedNodes([item.value+]);
          //     this.loadChildren(this.$refs.tree.getNode(item.value), resolve, reject)
          //     this.$refs.tree.getNode(item.value).children = this.tempData;
          //     this.$nextTick(() => {
          //       // 确保 DOM 更新后再展开节点
          //       this.$refs.tree.getNode(item.value).expanded = true;
          //     });
          //   }
          // })
        }
        // }, 10);
      }



    },
  • loadSelectedData函数和addSelectedNodes函数
loadSelectedData(tempData) {
      tempData.forEach(item => {
        console.log('tempData', item.value, item);

        // 0 不选 1全选 2半选
        if (item.selected == 1) {
          this.$nextTick(() => {
            // 确保 DOM 更新后再展开节点
            console.log('item.selected == 1', item.value)

            this.addSelectedNodes([item.value]);
          });

        } else if (item.selected == 2) {
          this.defaultExpandedNodes.push(item.value)
          this.loadSelectedData(item.children)

          // this.$refs.tree.getNode(item.value).children = this.tempData;
          // this.$nextTick(() => {
          //   // 确保 DOM 更新后再展开节点
          //   this.$refs.tree.getNode(item.value).expanded = true;
          // });
        }
      })
    },
    // 这个函数只能用于第一次获取列表时得到的selected数据
    addSelectedNodes(newNodeIds) {
      this.shouldCheckedKeys.push(newNodeIds[0])
      // 获取当前选中的节点 ID
      // const currentCheckedKeys = this.$refs.tree.getCheckedKeys();
      // console.log('currentCheckedKeys', currentCheckedKeys);

      // // 合并新的节点 ID
      // const updatedCheckedKeys = [...new Set([...currentCheckedKeys, ...newNodeIds])];
      // console.log('updatedCheckedKeys', updatedCheckedKeys);


      // 设置合并后的选中节点 ID
      this.$refs.tree.setCheckedKeys(this.shouldCheckedKeys);
    },

20241113更新-优化逻辑、修复bug

  • addSelectedNodes先不去勾选节点 注释掉:this.$refs.tree.setCheckedKeys(this.shouldCheckedKeys);
  • loadSelectedData在selected=1时勾选,此时节点已经展开 this.$refs.tree.setChecked(item.value, true, false)
// 这个函数只能用于第一次获取列表时得到的selected数据

    addSelectedNodes(newNodeIds) {

      console.log('addSelectedNodes', newNodeIds);
      this.shouldCheckedKeys.push(newNodeIds[0])

      // 获取当前选中的节点 ID
      // const currentCheckedKeys = this.$refs.tree.getCheckedKeys();
      // console.log('currentCheckedKeys', currentCheckedKeys);
      
      // // 合并新的节点 ID
      // const updatedCheckedKeys = [...new Set([...currentCheckedKeys, ...newNodeIds])];
      // console.log('updatedCheckedKeys', updatedCheckedKeys);
      
      // 设置合并后的选中节点 ID
      // this.$refs.tree.setCheckedKeys(this.shouldCheckedKeys);
    },

loadSelectedData(tempData) {

      tempData.forEach(item => {

        console.log('tempData', item.value, item.selected, item);
        // 0 不选 1全选 2半选
        if (item.selected == 1) {
          console.log('item.selected == 1', item.label);

          this.$nextTick(() => {

            // 确保 DOM 更新后再展开节点

            console.log('item.selected == 1', item.value)
            this.addSelectedNodes([item.value]);
            // setTimeout(() => {
            this.$refs.tree.setChecked(item.value, true, false)
            // }, 2000);
            // this.$nextTick(() => {
            //   this.$refs.tree.setChecked(item.value, true, false)
            // })
          });
        } else if (item.selected == 2) {
          console.log('item.selected == 2', item.label);
          this.defaultExpandedNodes.push(item.value)
          // this.loadSelectedData(item.children)
          // this.$refs.tree.getNode(item.value).children = this.tempData;
          // this.$nextTick(() => {
          //   // 确保 DOM 更新后再展开节点
          //   this.$refs.tree.getNode(item.value).expanded = true;

          // });

        }

      })

    },
async loadChildren(node, resolve, reject) {

      console.log(node, '如果是根节点,则直接提供数据如果是根节点,则直接提供数据');
      // this.getSelectedNodes()

      if (node.level === 0) {
        this.defaultExpandedNodes = []
        // this.categoryTreeData =
        // console.log('this.categoryTreeData', this.categoryTreeData);
        // console.log('props.currentId', props.currentId);
        this.tempData = []
        await qygApi.categoryTree({
          companyId: this.currentId,
          level: node.level + 1,
          // parentCategoryId: node.parentCategoryId,
        }).then(res => {
          // this.nodeData = res.data
          // console.log('this.nodeData', this.nodeData);
          if (res.code == 'success') {
            this.tempData = res.data
          }
        })

        // setTimeout(() => {
        console.log(this.tempData, 'tempDatatempDatatempData');
        resolve(this.tempData)
        // this.loadChildren(this.$refs.tree.getNode('11'), resolve, reject)
        if (!this.tempData) {

          reject()

        }
        // }, 1000);
        // this.shouldCheckedKeys = []
        this.shouldCheckedKeys.splice(0, this.shouldCheckedKeys.length);
        console.log('1-data', this.tempData);

        this.loadSelectedData(this.tempData)

        this.$nextTick(() => {
          // this.$refs.tree.setCheckedKeys(this.shouldCheckedKeys);

        })
      }
      if (node.level >= 1) {
        // const tempData = this.fetchChildrenNodeData(this.currentId, node.level + 1, node.value)
        console.log(node, 'nodenodenode');

        this.tempData = []
        console.log('starttime', dayjs());

        await qygApi.categoryTree({
          companyId: this.currentId,
          level: node.level + 1,
          parentCategoryId: node.data.value,
        }).then(res => {
          // this.nodeData = res.data
          // console.log('this.nodeData', this.nodeData);
          if (res.code == 'success') {
            this.tempData = res.data
          }

        })
        console.log('endtime', dayjs());

        // setTimeout(() => {

        console.log(this.tempData, 'tempDatatempDatatempDataaaaa');

        if (this.tempData.length == 0 && node.level == 3) {
          var self = this
          console.log('加载失败加载失败加载失败');

          self.$message.error('加载失败,请点击重新加载')
          node.loaded = false
          node.loading = false
          reject()
        } else {
          resolve(this.tempData)
          console.log('n-data', this.tempData);

          this.loadSelectedData(this.tempData)

          // this.tempData.forEach(item => {
          //   // 0 不选 1全选 2半选
          //   if (item.selected == 1) {
          //     this.addSelectedNodes([item.value]);
          //   } else if (item.selected == 2) {
          //     // this.addSelectedNodes([item.value+]);
          //     this.loadChildren(this.$refs.tree.getNode(item.value), resolve, reject)
          //     this.$refs.tree.getNode(item.value).children = this.tempData;
          //     this.$nextTick(() => {
          //       // 确保 DOM 更新后再展开节点
          //       this.$refs.tree.getNode(item.value).expanded = true;
          //     });
          //   }
          // })
        }
        // }, 10);
      }

    },