最近公司设计要求根据目录结构,横向展示。所以做了一个横向的思维导图,横向的树结构,横向的组织架构图,可以自定义节点颜色,样式,还可以导出为图片
话不多说,直接上图片,这个就是一个小例子
子组件,直接上代码,子组件的线条颜色,可以自己设置变量从父组件传入,我这里没写。
isUnfold 表示是否有下级
<template>
<div class="my-self-tree" ref="my-tree">
<div class="info-card">
<div class="card-item" v-for="(item, index) in data" :key="index">
<div
class="vertical-line"
:style="computedHeight(item.height, data.length, index)"
v-if="item.level !== 0"
></div>
<div class="horizontal-line" v-if="item.level !== 0"></div>
<div class="tree-node" :class="{'tree-node-1': item.level == 0&&item.isUnfold != 0}">
<div
class="tree-node-content"
:class="[handlItem(item)]"
@click="clickTreeNode(item)"
>
{{ item.name }}
</div>
</div>
<div
class="horizontal-line"
v-if="item.childNode && item.childNode.length !== 0"
></div>
<mytree
@nodeClick="clickTreeNode"
:data="item.childNode"
v-if="item.childNode && item.childNode.length !== 0"
></mytree>
</div>
</div>
</div>
</template>
<script>
export default {
name: "mytree",
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",
};
}
}
},
clickTreeNode(item) {
this.$emit("nodeClick", item);
},
handlItem(item) {
if (item.level == 0) {
return 'has-background'
}else {
if (item.isUnfold == 1) {//中间节点
let flag = this.hasZeroCountNode(item.childNode);
console.log(flag, 'flag')
if (item.level == 1) {
return flag ? 'font-color-black border-black' : 'font-color-green border-green';
} else {
return flag ? 'font-color-black' : 'font-color-green';
}
} else if (item.isUnfold == 0) {//最后一个节点
if (item.level == 1) {
return item.count == 0 ? 'font-color-red border-red' : 'font-color-green border-green'
} else {
return item.count == 0 ? 'font-color-red' : 'font-color-green'
}
}
}
},
hasZeroCountNode(nodes) {
//不含当前节点的count判断,判断所有子节点
for (let node of nodes) {
if (node.count === 0) {
return true;
}
if (node.childNode && this.hasZeroCountNode(node.childNode)) {
return true;
}
}
return false;
//含当前节点的count判断
// if (node.count === 0) {
// return true; // 如果找到节点的count为0,立即返回true
// }
// if (node.childNode && node.childNode.length > 0) {
// // 如果节点有子节点,则递归检查子节点
// return node.childNode.some(child => this.hasZeroCountNode(child));
// }
// return false; // 如果节点和其子节点都不满足条件,返回false
}
},
components: {},
mounted() {},
};
</script>
<style lang="scss" scoped>
:root .my-self-tree {
// height: 100%;
// width: 100%;
.vertical-line {
position: relative;
// display: inline-block;
width: 0.5px;
background: #009694;
transform:scale(2, 1);
}
.card-item {
margin:0;padding:0;
display: flex;
align-items: center;
.horizontal-line {
min-width: 30px !important;
// display: inline-block;
height: 0.5px;
background: #009694;
transform:scale(1 , 2);
position: relative;
}
.horizontal-line::before {
content:'';
position:absolute;
height: 1px;
width:2px;
right:-1px;
background: #009694;
}
.horizontal-line::after {
content:'';
position:absolute;
height: 1px;
width:2px;
left:-1px;
background: #009694;
}
}
.tree-node {
cursor: pointer;
height: 30px;
position: relative;
&:nth-child(1)::after {
display: none;
}
// &:nth-child(1)::before {
// position: absolute;
// content: "";
// width: 8px;
// display: inline-block;
// height: 8px;
// border-radius: 4px;
// top: 50%;
// right: -4px;
// transform: translateY(-50%);
// background: #009694;
// }
.tree-node-content {
display: flex;
position: relative;
justify-content: center;
align-items: center;
width: auto;
height: 100%;
border: none;
border-radius: 4px;
color: #000;
white-space: nowrap !important;
padding: 0 10px;
}
.has-background {
color: white;
background: #009694;
}
.border-green {
border: 1px solid #009694;
}
.border-black {
border: 1px solid #000;
}
.border-red {
border: 1px solid #FF6767;
}
.font-color-green {
color: #009694;
}
.font-color-black {
color: #000;
}
.font-color-red {
color: #FF6767;
}
}
.tree-node::after {
position: absolute;
content: "";
width: 8px;
display: inline-block;
height: 8px;
border-radius: 4px;
top: 50%;
left: -4px;
transform: translateY(-50%);
background: #009694;
}
.tree-node-1::before {
position: absolute;
content: "";
width: 8px;
display: inline-block;
height: 8px;
border-radius: 4px;
top: 50%;
right: -4px;
transform: translateY(-50%);
background: #009694;
}
}
</style>
这里是父组件
<el-popconfirm
placement="top-end"
title="是否需要导出为图片?"
@confirm="exportFn"
>
<el-button
slot="reference"
style="margin-left: 10px"
type="primary"
class="fliter-btn icons-btn"
size="mini"
><i class="qhFileManage icon-daochu" style="font-size: 14px;"></i> 导出
</el-button>
</el-popconfirm>
<tree :data="dataInfo" @nodeClick="nodeClick" id="mytree" style="height: 100%;"></tree>
//处理数据
//temporaryData 为实际获取的数据 ,temporaryData1 是做例子写的数据
handleData(temporaryData) {
//自行调试测试数据,后面换成正式数据
let temporaryData1 = [
{
id: 1,
level: 0,
name: "部门名称啊",
childNode: [
{
id: 11,
level: 1,
name: "自己测试数据",
isUnfold: 1,
childNode: [
{
id: 1111111,
level: 2,
name: "所有下级节点count>0",
isUnfold: 1,
childNode: [
{
id: 1111111,
level: 3,
name: "2ge",
count: 2,
isUnfold: 0,
},
{
id: 1111111,
level: 3,
name: 1,
isUnfold: 1,
childNode: [
{
id: 1111111,
level: 4,
name: "2",
isUnfold: 1,
childNode: [
{
id: 1111111,
level: 4,
name: "1ge",
count: 1,
isUnfold: 0,
},
],
},
],
},
{
id: 1111111,
level: 3,
name: "2ge",
count: 2,
isUnfold: 0,
},
],
},
{
id: 1111111,
level: 2,
name: "所有下级节点count=0",
isUnfold: 1,
childNode: [
{
id: 1111111,
level: 3,
name: "0ge",
count: 0,
isUnfold: 0,
},
{
id: 1111111,
level: 3,
name: 1,
isUnfold: 1,
childNode: [
{
id: 1111111,
level: 4,
name: "0ge",
count: 0,
isUnfold: 0,
},
],
},
{
id: 1111111,
level: 3,
name: "0ge",
count: 0,
isUnfold: 0,
},
],
},
{
id: 1111111,
level: 2,
name: "所有下级节点存count=0,>0",
isUnfold: 1,
childNode: [
{
id: 1111111,
level: 3,
name: "0ge",
count: 0,
isUnfold: 0,
},
{
id: 1111111,
level: 3,
name: 1,
isUnfold: 1,
childNode: [
{
id: 1111111,
level: 4,
name: "1ge",
count: 1,
isUnfold: 0,
},
],
},
{
id: 1111111,
level: 3,
name: "1ge",
count: 1,
isUnfold: 0,
},
],
},
],
},
],
isUnfold: 1,
},
];
let fixedData = temporaryData.map((item) => {
return this.traveTree(item);
});
console.log(fixedData, "fixedData");
this.dataInfo = fixedData;
},
// traveTree这里是给每个节点设置高度,
traveTree(nodeInfo) {
let childrenInfo = nodeInfo.childNode;
if (!childrenInfo || childrenInfo.length == 0) {
nodeInfo.height = 40;
} else {
childrenInfo.map((item) => {
this.traveTree(item);
});
nodeInfo.height = childrenInfo.reduce((preV, n) => {
return preV + n.height;
}, 0);
}
return nodeInfo;
},