这是我第一次写文章,文笔不好,希望大家多多担待!
上午遇到一个需求,正好没有其他事,就随手记录一下解决过程
业务场景主要是懒加载,数据多的情况下。业务需求是进行树搜索后,自动展开树节点,因为列表较长,需要自动滚动到节点所在位置,又因为是懒加载,所以需考虑节点的加载情况。
先来看下最终实现效果
接口比较慢所以看起来有点卡~~
实现思路
整体的功能还是比较简单,具体的思路就是拿整个树的数据,对比需要展开的节点拿到index,再获取到每个node的高度,相乘即可拿到这一层需要滚动的高度,等待懒加载的完成,依次逐层对比计算即可。
DOM的获取
首先要拿到需要滚动的元素,即有滚动条的元素。
const treeNode = this.$refs.getTreeDataQY.$refs.comOrgTree.$el.querySelector('.org-tree-con').querySelector('.ant-tree-wrapper')
然后拿到每一个第一个tree节点的高度,用于之后计算应该滚动的高度。
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)
})
},
以上就是该功能的全部实现过程,仅作记录。 如果大家有更好的实现方法,可以评论区一起讨论。