就是这样的,横线就是名字将就看吧
首先vue创建组件:
<template>
<table v-if="treeData.data">
<tr>
<td :colspan="Array.isArray(treeData.children) ? treeData.children.length * 2 : 1" :class="{
parentLevel: Array.isArray(treeData.children) && treeData.children.length,
extend: Array.isArray(treeData.children) && treeData.children.length && treeData.extend
}" >
<div :class="{ node: true, hasMate: treeData.mate }">
<div class="person" :class="treeData.rankNum==4 ? 'rootNode' :''">
<div class="right" @contextmenu="$emit('click-node', treeData)">
<div class="name"><span>{{ treeData.data }}</span></div>
</div>
</div>
</div>
<div class="extend_handle" v-if="Array.isArray(treeData.children) && treeData.children.length"
@click="toggleExtend(treeData)">
</div>
</td>
</tr>
<!-- 这是一个递归组件,注意,这里还要调用,需要传递的数据这里也要传递,否则操作时拿不到子级的数据 -->
<tr v-if="Array.isArray(treeData.children) && treeData.children.length && treeData.extend">
<td v-for="(children, index) in treeData.children" :key="index" colspan="2" class="childLevel">
<treeChart :json="children" @click-node="$emit('click-node', $event)" />
</td>
</tr>
</table>
</template>
<script>
export default {
name: "treeChart",
props: ["json"],
data() {
return {
treeData: {}
}
},
created(){
},
watch: {
// 遍历当前的数据
json: {
handler: function (Props) {
let extendKey = function (jsonData) {
jsonData.extend = (jsonData.extend === void 0 ? true : !!jsonData.extend);
if (Array.isArray(jsonData.children)) {
jsonData.children.forEach(c => {
extendKey(c)
})
}
return jsonData;
}
if (Props) {
this.treeData = extendKey(Props);
}
},
immediate: true
}
},
methods: {
toggleExtend: function (treeData) {
treeData.extend = !treeData.extend;
this.$forceUpdate();
},
}
}
</script>
<style scoped lang="scss">
table {
margin: 0 auto;
border-collapse: separate !important;
border-spacing: 0 !important;
}
td {
position: relative;
vertical-align: top;
padding: 0 0 40px 0;
text-align: center;
}
.extend_handle:hover:before {
border-color: #333 #333 transparent transparent;
}
.extend .extend_handle:before {
transform: rotateZ(-45deg);
}
.extend::after {
content: "";
position: absolute;
left: 50%;
bottom: 15px;
height: 20px;
border-left: 2px solid #ccc;
transform: translate3d(-1px, 0, 0)
}
.childLevel {
padding: 0px;
}
.childLevel::before {
content: "";
position: absolute;
left: 50%;
bottom: 100%;
height: 15px;
border-left: 2px solid #ccc;
transform: translate3d(-1px, 0, 0)
}
.childLevel::after {
content: "";
position: absolute;
left: 0;
right: 0;
top: -15px;
border-top: 2px solid #ccc;
}
.childLevel:first-child:before,
.childLevel:last-child:before {
display: none;
}
.childLevel:first-child:after {
left: 50%;
height: 15px;
border: 2px solid;
border-color: #ccc transparent transparent #ccc;
border-radius: 6px 0 0 0;
transform: translate3d(1px, 0, 0);
}
.childLevel:last-child:after {
right: 50%;
height: 15px;
border: 2px solid;
border-color: #ccc #ccc transparent transparent;
border-radius: 0 6px 0 0;
transform: translate3d(-1px, 0, 0);
}
.childLevel:first-child.childLevel:last-child::after {
left: auto;
border-radius: 0;
border-color: transparent #ccc transparent transparent;
transform: translate3d(1px, 0, 0)
}
.node {
position: relative;
display: inline-block;
margin: 0 0.5em;
box-sizing: border-box;
text-align: center;
}
.node .person {
position: relative;
display: inline-block;
z-index: 2;
overflow: hidden;
border-radius: 4px;
display: flex;
/* padding: 17px 0px 20px 10px; */
}
.node .person:nth-child(1) {
border: 1px solid #0084FF;
background: #0084FF;
}
.node .person .avat {
display: block;
width: 4em;
height: 60px;
overflow: hidden;
background: #fff;
border-radius: 8px;
border: 1px solid #ccc;
box-sizing: border-box;
}
.right {
text-align: center;
color: #fff;
width: 100%;
margin: 0 10px;
}
.node .person .avat img {
width: 100%;
height: 60px;
}
.node .person .name {
height: 2em;
line-height: 2em;
overflow: hidden;
color: #fff;
letter-spacing: 1px;
width: 140px;
}
.node.hasMate::after {
content: "";
position: absolute;
left: 2em;
right: 2em;
top: 2em;
border-top: 2px solid #ccc;
z-index: 1;
}
.rootNode {
.right {
margin: 0px;
.name {
width: 30px;
height: 100px;
line-height: 1.5em;
display: flex;
align-items: center;
}
}
}
</style>
在需要使用此组件的地方:
<template>
<div class="flowChart">
<treeChart :json="data1" :class="{ landscape: '' }" @click-node="clickNode" />
<div class="gl_prs_ctn" :style='[contextstyle]'>
<ul class='gl_prs_li'>
<li>添加</li>
<li>详情</li>
<li>编辑</li>
<li>删除</li>
</ul>
</div>
</div>
</template>
<script>
import treeChart from "@/components/treeChart/treeChart";
export default {
components: {
treeChart
},
data() {
return {
landscape: [],
data1: {
data: 'XX:XX',
children: [
{
data: 'XXXXX:XX',
children: [
{
data: 'XXXXX',
children: [
{
data: 'XXX',
rankNum: ["rootNode"],
},
{
data: 'XXX',
rankNum: ["rootNode"],
},
]
},
{
data: 'XXXXX',
children: [
{
data: 'XX',
rankNum: ["rootNode"],
},
{
data: 'XXX',
rankNum: ["rootNode"],
},
]
},
{
data: 'XXXXX',
children: [
{
data: 'XXX',
rankNum: ["rootNode"],
},
{
data: 'XX',
rankNum: ["rootNode"],
},
]
},
{
data: 'XXXXX',
children: [
{
data: 'XX',
rankNum: ["rootNode"],
},
{
data: 'XX',
rankNum: ["rootNode"],
},
{
data: 'XX',
rankNum: ["rootNode"],
},
{
data: 'XX',
rankNum: ["rootNode"],
},
]
},
]
},
],
},
contextstyle: {
display: 'none',
right: '0px',
top: '0px',
left: '0px',
bottom: '0px',
},
}
},
created() {
document.oncontextmenu = () => { return false }
document.addEventListener("click", (event) => {
if (this.contextstyle.display == 'block') {
this.contextstyle.display = 'none'
}
})
this.getFramework();
},
mounted() {
},
methods: {
clickNode(node) {
if (window.event.x + 188 > document.documentElement.clientWidth) {
this.contextstyle.left = 'unset';
this.contextstyle.right = document.documentElement.clientWidth - window.event.x + 'px';
} else {
this.contextstyle.left = window.event.x + 'px';
}
if (window.event.y + 166 > document.documentElement.clientHeight) {
this.contextstyle.top = 'unset';
this.contextstyle.bottom = document.documentElement.clientHeight - window.event.y + 'px';
} else {
this.contextstyle.top = window.event.y + 'px';
}
this.contextstyle.display = 'block';
},
}
}
</script>
<style lang="scss" scoped>
</style>