andv tree 懒加载的树形组件实现搜索并滚动定位到对应位置的功能

843 阅读1分钟

这是我第一次写文章,文笔不好,希望大家多多担待!

上午遇到一个需求,正好没有其他事,就随手记录一下解决过程

业务场景主要是懒加载,数据多的情况下。业务需求是进行树搜索后,自动展开树节点,因为列表较长,需要自动滚动到节点所在位置,又因为是懒加载,所以需考虑节点的加载情况。

先来看下最终实现效果

接口比较慢所以看起来有点卡~~ GIF 2022-3-28 15-31-40.gif

实现思路

整体的功能还是比较简单,具体的思路就是拿整个树的数据,对比需要展开的节点拿到index,再获取到每个node的高度,相乘即可拿到这一层需要滚动的高度,等待懒加载的完成,依次逐层对比计算即可。

DOM的获取

首先要拿到需要滚动的元素,即有滚动条的元素。

const treeNode =  this.$refs.getTreeDataQY.$refs.comOrgTree.$el.querySelector('.org-tree-con').querySelector('.ant-tree-wrapper')

然后拿到每一个第一个tree节点的高度,用于之后计算应该滚动的高度。 Snipaste_2022-03-28_15-46-22.png

const listNode = treeNode.querySelector('li > span.ant-tree-node-content-wrapper')
const listNodeHeight = listNode.clientHeight + 8

滚动高度的计算

// val中包含了 expandKey=定位到目标元素之前所有需要展开的节点 treedata=整颗树的数据源
let scrollTop = 0
const expandList = JSON.parse(JSON.stringify(val.expandKey))
// 不需要顶级节点 所以删除第一个
expandList.shift()
// 从最顶级节点依次往下一层循环对比
this.currentItem = val.treedata[0]
expandList.map(async item => {
    // 因为是懒加载 所以要等待当前层加载完毕后再能对比key 然后才能进行下一层的对比 所以要用异步 等待promise的返回
    await this.awaitChildren().then(res => {
       if (res.children) {
           // 查找到当前所展开的key在父节点children中的index 乘以高度拿到这一层所需滚动的高度 依次叠加
           // dmcod就是key
          let currentIndex = res.children.findIndex(v => v.dmcod === item.dmcod)
              scrollTop += (currentIndex + 1) * listNodeHeight
              treeNode.scrollTo(0, scrollTop)
           }
            // 进入下一层循环 原本使用传参的方式类似递归 不知道为什么值改了 但是传参的值没改 导致不能进入下一层循环 所以使用this来接收
            this.currentItem = res.children? res.children.find(v => v.dmcod === item.dmcod) : res
        })
    })

promise监听树节点

此处使用promise,主要由于面的map执行时不确定节点的children是否加载完成,所以使用await持续读取节点,等到节点加载出children就resolve,进行下一层的节点循环

awaitChildren () {
      return new Promise(resolve => {
        setTimeout(() => {
            // 如果有children就返回
          if (this.currentItem.children) {
            resolve(this.currentItem)
          } else {
            // 没有就继续读取,直到拿到children再返回
            return resolve(this.awaitChildren())
          }
        }, 200)
      })
    }

全部代码

// 跳转到指定位置的功能
    jumpToPosition (val) {
        const treeNode =  this.$refs.getTreeDataQY.$refs.comOrgTree.$el.querySelector('.org-tree-con').querySelector('.ant-tree-wrapper')
        const listNode = treeNode.querySelector('li > span.ant-tree-node-content-wrapper')
        const listNodeHeight = listNode.clientHeight + 8
        let scrollTop = 0
        const expandList = JSON.parse(JSON.stringify(val.expandKey))
        expandList.shift()
        // 当前是哪个元素
        let currentItem = val.treedata[0]
        this.currentItem = currentItem
        expandList.map(async item => {
          await this.awaitChildren().then(res => {
            if (res.children) {
              let currentIndex = res.children.findIndex(v => v.dmcod === item.dmcod)
              // +1是因为需要加上父节点的高度
              scrollTop += (currentIndex + 1) * listNodeHeight
              treeNode.scrollTo(0, scrollTop)
            }
            this.currentItem = res.children? res.children.find(v => v.dmcod === item.dmcod) : res
          })
        })
      }
    },
    awaitChildren () {
      return new Promise(resolve => {
        setTimeout(() => {
          if (this.currentItem.children) {
            resolve(this.currentItem)
          } else {
            return resolve(this.awaitChildren())
          }
        }, 200)
      })
    },

以上就是该功能的全部实现过程,仅作记录。 如果大家有更好的实现方法,可以评论区一起讨论。