實現(xiàn)效果圖如下:
image.png
數(shù)據(jù)格式 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: [
]
}
]
}
]
}
]
實現(xiàn)代碼 遞歸調(diào)用最小實現(xiàn)單元 組件NodeTree.vue
<!--
* @Descripttion: 橫向樹實現(xiàn)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>
父組件調(diào)用 Parent.vue
引入NodeTree.vue
<!--
* @Descripttion: 橫向組織架構(gòu)圖實現(xiàn)
* @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>
實現(xiàn)思路
抽取最小實現(xiàn)單元继榆,然后循環(huán)遞歸即可
image.png
(1)左右兩端水平線 實現(xiàn):
image.png
<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)連接后代的縱軸部分實現(xiàn):
image.png
需要知道每個后代的高度集币,然后第一個后代的高度/2 + 中間所有后代的高度和+ 最后一個后代的高度/2 就是所需要縱軸的高度
高度的具體實現(xiàn)代碼: 假設最后一層后代的高度為70
a.初始數(shù)據(jù)處理: 利用二叉樹的 后序遍歷方法先給每一個節(jié)點添加上高度屬性
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"
};
}
}
}