最近公司设计要求根据目录结构,横向展示。所以做了一个横向的思维导图,横向的树结构,横向的组织架构图,可以自定义节点颜色,样式,还可以导出为图片
话不多说,直接上图片,这个就是一个小例子
子组件,直接上代码,子组件的线条颜色,可以自己设置变量从父组件传入,我这里没写。
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"><divclass="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}"><divclass="tree-node-content":class="[handlItem(item)]"@click="clickTreeNode(item)">{{ item.name }}</div></div><divclass="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-popconfirmplacement="top-end"title="是否需要导出为图片?"@confirm="exportFn"><el-buttonslot="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;},