实现效果图如下:
数据格式 tree
let dataInfo = [
{
name: "root",
value: "root",
children: [
{
name: "child1",
value: "一级1",
children: [
{
name: "child2",
value: "二级1",
children: []
},
{
name: "child2",
value: "二级2",
children: []
}
]
},
{
name: "child1",
value: "一级2",
children: [
{
name: "child2",
value: "二级3",
children: [
]
}
]
}
]
}
]
实现代码 递归调用最小实现单元 组件NodeTree.vue
<!--
* @Descripttion: 横向树实现demo
* @version:
* @Author: year
-->
<template>
<div class="item-content" ref="cardItemDiv">
<div class="info-card">
<div class="card-item" v-for="(item, index) in data" :key="index">
<span
class="vertical-line"
:style="computedHeight(item.height, data.length, index)"
v-if="item.name !== 'root'"
></span>
<span class="horizontal-line" v-if="item.name !== 'root'"></span>
<div class="div-card">
<div>{{item.value}}</div>
</div>
<span class="horizontal-line" v-if="item.children&&item.children.length !== 0"></span>
<equip-list :data="item.children" v-if="item.children&&item.children.length !== 0"></equip-list>
</div>
</div>
</div>
</template>
<script>
export default {
name: "equipList",
props: {
data: Array
},
data() {
return {
};
},
methods: {
computedHeight(pheight, length, index) {
if (length == 1 || length == 0) {
return {
height: "0px",
display: "none"
};
} else {
let height = 0;
let marginTop = 0;
let marginB = 0;
if (index == 0) {
height = pheight / 2;
marginTop = height;
return {
height: height + "px",
"margin-top": marginTop + "px"
};
}
if (index == length - 1) {
height = pheight / 2;
marginB = height;
return {
height: height + "px",
"margin-bottom": marginB + "px"
};
} else {
height = pheight;
return {
height: height + "px"
};
}
}
}
},
components: {},
mounted() {
}
};
</script>
<style lang='scss' scoped>
.item-content {
height: 100%;
width: 100%;
display: flex;
.vertical-line {
display: inline-block;
width: 2px;
background: #eaeaea;
}
.card-item {
display: flex;
align-items: center;
.horizontal-line {
width: 40px;
display: inline-block;
height: 2px;
background: #eaeaea;
}
}
}
.div-card {
height: 77px;
& > div {
display: flex;
justify-content: center;
align-items: center;
width: 220px;
height: 67px;
background: inherit;
background-color: rgba(253, 253, 253, 1);
border: none;
border-radius: 4px;
-moz-box-shadow: 1px 3px 5px rgba(0, 0, 0, 0.2);
-webkit-box-shadow: 1px 3px 5px rgba(0, 0, 0, 0.2);
box-shadow: 1px 3px 5px rgba(0, 0, 0, 0.2);
color: #8d8d8e;
}
}
</style>
父组件调用 Parent.vue
引入NodeTree.vue
<!--
* @Descripttion: 横向组织架构图实现
* @version:
* @Author: year
-->
<template>
<div class="shopping-table-info">
<NodeTree :data="dataInfo" />
</div>
</template>
<script>
import NodeTree from "./ShoppingEquipList";
export default {
data() {
return {
dataInfo: []
};
},
methods: {
getDataInfo() {
let dataInfo = [
{
name: "root",
value: "root",
children: [
{
name: "child1",
value: "一级1",
children: [
{
name: "child2",
value: "二级1",
children: []
},
{
name: "child2",
value: "二级2",
children: []
}
]
},
{
name: "child1",
value: "一级2",
children: [
{
name: "child2",
value: "二级3",
children: []
}
]
}
]
}
];
let fixedData = dataInfo.map(item => {
return this.traveTree(item);
});
this.dataInfo = fixedData;
},
traveTree(nodeInfo) {
let childrenInfo = nodeInfo.children;
if (!childrenInfo || childrenInfo.length == 0) {
nodeInfo.height = 77;
} else {
childrenInfo.map(item => {
this.traveTree(item);
});
nodeInfo.height = childrenInfo.reduce((preV, n) => {
return preV + n.height;
}, 0);
}
return nodeInfo;
}
},
components: {
NodeTree
},
mounted() {
this.getDataInfo();
}
};
</script>
实现思路
抽取最小实现单元,然后循环递归即可
(1)左右两端水平线 实现:
<span class="horizontal-line" v-if="item.name !== 'root'"></span>
<span class="horizontal-line" v-if="item.children&&item.children.length !== 0"></span>
span标签画两条水平线,然后利用flex布局,居中布局即可。最小单元后面的水平线判断没有后代的时候 不显示即可
(2)连接后代的纵轴部分实现:
需要知道每个后代的高度,然后第一个后代的高度/2 + 中间所有后代的高度和+ 最后一个后代的高度/2 就是所需要纵轴的高度
高度的具体实现代码: 假设最后一层后代的高度为70
a.初始数据处理: 利用二叉树的 后序遍历方法先给每一个节点添加上高度属性
traveTree(nodeInfo) {
let childrenInfo = nodeInfo.children;
if (!childrenInfo || childrenInfo.length == 0) {
nodeInfo.height = 77;
} else {
childrenInfo.map(item => {
this.traveTree(item);
});
nodeInfo.height = childrenInfo.reduce((preV, n) => {
return preV + n.height;
}, 0);
}
return nodeInfo;
}
b.计算链接线高度
computedHeight(pheight, length, index) {
if (length == 1 || length == 0) {
return {
height: "0px",
display: "none"
};
} else {
let height = 0;
let marginTop = 0;
let marginB = 0;
if (index == 0) {
height = pheight / 2;
marginTop = height;
return {
height: height + "px",
"margin-top": marginTop + "px"
};
}
if (index == length - 1) {
height = pheight / 2;
marginB = height;
return {
height: height + "px",
"margin-bottom": marginB + "px"
};
} else {
height = pheight;
return {
height: height + "px"
};
}
}
}