项目要求el-tree懒加载, 因为树结构中的数据太多, 所以每层节点需要使用分页多次加载,具体的实现效果如下图:
<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>