el-tree分页懒加载的实现

文章描述了一个在Vue.js项目中使用el-tree组件实现懒加载和分页加载树结构数据的解决方案。通过重写load方法,记录节点信息和resolve函数,以及处理加载更多节点的逻辑,实现了当树结构数据量过大时的高效加载策略。
摘要由CSDN通过智能技术生成

功能描述:

项目要求el-tree懒加载, 因为树结构中的数据太多, 所以每层节点需要使用分页多次加载,具体的实现效果如下图:
在这里插入图片描述

实现思路:

  1. 懒加载很简单, 参照element-ui文档即可
  2. 根节点的加载更多也简单, 记录初始的node及resolve即可
  3. 其他节点的分页加载逻辑就稍微复杂一点, 需要复写el-tree自带的load方法,load方法内携带两个返回参数,一个是node,一个是resolve,即懒加载数据必须是通过resolve就是return 将数据带回,所以在初次加载的时候就需要记录下当前的node和resolve, 其次就是记录当前节点下数据的总数并再每次点击加载更多的时候对当前节点下的页码进行累加

实现代码

<template>
  <div v-dee-loading="loading" class="demo">
          <el-tree
            ref="treeRef"
            v-dee-loading="list.loading"
            accordion
            node-key="id"
            :load="loadNode"
            lazy
            :props="defaultProps"
            :expand-on-click-node="false"
            @node-click="handleNodeClick"
          >
            <div slot-scope="{ node, data }" class="custom-tree-node">
              <!-- 查看更多 -->
              <span
                v-if="data.id ==='loadmore'"
                class="tree-node loadmore"
                @click="loadMoreNode(node,data)"
              >
                <el-link>{{ node.label }}</el-link>
              </span>
              <!-- 普通节点 -->
              <span v-else class="span-tree-node">
                {{ node.label }}
              </span>
            </div>
          </el-tree>
          <!-- 根节点数据加载更多(分页)-->
          <div class="more-bar">
            <span v-if="curpage[0]* pageSize < total[0]" class="more" @click="loadMoreOut">加载更多</span>
            <span v-else>已全部加载!</span>
          </div>
          </div>
</template>
<script>
export default {
  name: 'Demo',
  components: {},
  props: {},
  data() {
    return {
      loading: false,
      list: {
        loading: false,
        isExpand: false
      },
      defaultProps: {
        label: 'name',
        children: 'children',
        isLeaf: 'leaf'
      },
      curNode: {},
      resolveFunc: [],
      node0: {},
      resolveFunc0: function() {},
      total: {},
      curpage: {},
      pageSize: 100
    }
  },
  created() {},
  mounted() {
  },
  methods: {
    async  loadNode(node, resolve, parentNode = []) {
      const id = node?.data?.id || 0
      //  记录当前节点的当前页码 
      !this.curpage[id] && (this.curpage[id] = 1)
      this.curNode = node
      // 节点各自的resolve
      this.resolveFunc.push({ id: id, resolve: resolve })
      this.resolveFunc = this.resolveFunc.filter((item, index, self) => {
        return self.findIndex(x => x.id === item.id) === index
      })
      if (node.level === 0) {
        this.node0 = node
        this.resolveFunc0 = resolve
        return resolve(await this.getTreeData(null, node.level))
      } else if (node.level >= 1) {
        const data = await this.getTreeData(node.data, node.level)
        // 当前界面的数据小于总数据
        if (this.curpage[id] * this.pageSize < this.total[id]) {
          const nearName = data[data.length - 1].name
          data.push({ name: '查看更多', id: 'loadmore', nearName: nearName,leaf: true, disabled: true })
        }
        // 查看更多加载需根据各自的resolve加载数组数据
        if (parentNode && parentNode.length > 0) {
          parentNode.push(...data)
          return resolve(parentNode)
        } else {
          return resolve(data)
        }
      } else {
        return resolve([]) // 防止该节点没有子节点时一直转圈的问题出现
      }
    },
    getTreeData(nodeData, nodeLevel, node) {
      const curId = nodeData?.id || 0
      this.list.loading = true
      let tags = []
      const params = {xxx:xxx}   //  此处为请求所需参数, 已省略
      return matchingQuery(params).then(res => {
        if (!res.items || !res.items.content) return
        tags = res.items.content || []
        tags.forEach((item, index) => { // 节点需要构建为 tree 的结构
          item.name = `${item.name}-${item.code}`
          item.id = parseInt(Math.random() * 1000000000000, 10)
          item.leaf = false
        })
        this.list.loading = false
        //   存储当前节点下的数据总数
        this.total[curId] = res.items.totalElements   
        return tags
      }).catch(err => {
        console.log('err: ', err)
      }).finally(() => {
        this.list.loading = false
        return tags
      })
    },
    loadMoreNode(node, data) {
      if (data.id === 'loadmore') {
        const nodeParentKey = node.parent.key ? node.parent.key : ' '
        const childNode = {
          data: {
            id: nodeParentKey,
            name: data.nearName,
          },
          level: node.level - 1
        }
        let resolve = ''
        let parentNode = node.parent.childNodes.map(({ key: id, label: name }) => {
          return { name, id }
        })
        // 剔除自定义的“查看更多”项的数据
        if (parentNode.length > 0) {
          parentNode = parentNode.slice(0, -1)
        }
        // 选取resolve返回
        if (parentNode.length <= this.total[nodeParentKey]) {
          resolve = this.resolveFunc.filter((item) => {
            return item.id === nodeParentKey
          })
          //  点击更多时, 当前节点的当前页+1
          this.curpage[nodeParentKey] += 1
          // 调用原生Tree load方法
          this.$refs.treeRef.load(childNode, resolve[0].resolve, parentNode)
        }
      }
    },
    //  根节点加载更多   (为了效果更好一点, 所以根节点的加载方式单独设置样式)
    loadMoreOut(node) {
      if (this.curpage[0] * this.pageSize < this.total[0]) {
        this.curpage[0] += 1
        this.loadNode(this.node0, this.resolveFunc0)
      }
    },
//   此处为重新加载树结构的方法
    reloadTree() {
      this.curpage = {}
      this.node0.childNodes = []
      this.loadNode(this.node0, this.resolveFunc0)
    },
    handleNodeClick(){}
  }
}
</script>
<style  lang="scss">
  .demo{
    height: 100%;
    box-sizing: border-box;
   background-color: #F1F4F5;
   .more-bar {
      margin: 10px auto;
      text-align: center;
      font-size: 12px;
      color: #999;
    }

    .more {
      margin: auto;
      margin-top: 20px;
      color: #2f90e2;
      height: 26px;
      line-height: 26px;
      padding: 0 20px;
      background: rgba(231, 242, 255, 1);
      border-radius: 13px;
      display: inline-block;
      cursor: pointer;
    }
  }
 </style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值