1. 实现方案
- 方案1:基于 css + div,已完美实现,开箱即用
- 方案2:基于 canvas / svg,待实现
2. css+div 绘制思路
主要的绘制思路如下:
- 每一层是一个 flex 容器
- 非叶子节点,有下方垂直线,还有下方的横线
- 非根节点,有上方的垂直线
- 每一层的首节点 和 尾节点,分别有向左和向向右的遮盖线
3. 细节与特性
- 节点的尺寸可配置,已实现;
- 当树不是对称时,图的对称性考虑,已实现;
- 节点可折叠,已实现;
- 节点的内容可提供插槽,已实现;
- 每个节点的大小可以不一样,已实现;
- 支持多个根结点,已实现;
- 支持动态加载子节点,已实现;
4. 代码和效果演示
x4VEzeyj0N.gif<template>
<div class="wrapper">
<div class="m-container">
<TreeGraphV1
ref="treeRef"
:handleCollapse="mHandleCollpase"
:treeData="treeData"
:boxSize="boxSize"
lazyKey="hasChildren"
:getContentWidth="getContentWidth"
/>
</div>
</div>
</template>
<script lang="jsx">
import JsonData from './DemoV1.json'
import TreeGraphV1 from '../components/TreeGraphV1.vue'
export default {
components: {
TreeGraphV1
},
data() {
return {
treeData: JsonData,
boxSize: {
height: 40,
margin: 15
}
};
},
methods: {
// 自定义插槽
renderContent (node) {
return <span>{node.name}</span>
},
// 获取容器宽度
getContentWidth(node) {
return Math.max(node.name.length * 15 + 20, 60)
},
// 重新渲染
refresh() {
this.$refs.treeRef.reLayout()
},
// 处理懒加载节点
mHandleCollpase(node, cb) {
if (!node.children) {
this.treeData = JSON.parse(JSON.stringify(this.treeData))
}
// 掉用 cb 进行再次渲染
setTimeout(cb, 100);
}
}
};
</script>
<style lang="less" scoped>
.m-container {
overflow: auto;
width: 100vw;
height: 100vh;
border: 1px solid #eee;
}
</style>
5. 本文总结
本文中的实现方案,是在未做现有方法的研究下得出的,也未参考他人的实现,可能并不正确,仅提供参考。后续,待实现方案2后,我会去找一些其他的实现方案或者代码,进行对比,重新梳理本文。
网友评论