创建组件名称 TreeNodeView.vue
<template>
<div class="tree-node">
<div class="node">{{ rootNodeName }}</div>
<div class="children" :style="childrenLineStyle">
<div class="child-node" v-for="node in childNodes" :key="node.id">
<div class="node">{{ node.name }}</div>
</div>
</div>
</div>
</template>
<script setup>
import {computed, ref, onMounted} from 'vue';
const props = defineProps({
childNodes: {
type: Array,
required: true
},
rootNodeName: {
type: String,
required: true,
},
});
const childNode = ref(null);
const childrenWidth = ref(null);
const childrenMarginLeft = ref(null);
const childrenLineStyle = computed(() => {
if (!childNode.value) {
return {};
}
const getWidth = (element) => {
const style = getComputedStyle(element);
return parseFloat(style.width) + parseFloat(style.marginLeft) + parseFloat(style.marginRight);
};
let allNodeWidth = Array.from(childNode.value).reduce((total, node) => total + getWidth(node), 0);
const firstNodeWidth = getWidth(childNode.value[0]) / 2;
let lastNodeWidth = 0;
if (childNode.value.length > 1) {
lastNodeWidth = getWidth(childNode.value[childNode.value.length - 1]) / 2;
}
childrenWidth.value = `${allNodeWidth - firstNodeWidth - lastNodeWidth}px`;
childrenMarginLeft.value = `${firstNodeWidth}px`;
return {};
});
onMounted(() => {
childNode.value = document.querySelectorAll('.child-node');
});
</script>
<style>
.tree-node {
display: inline-flex;
flex-direction: column;
align-items: center;
}
.node {
border: 1px solid #000;
padding: 5px;
position: relative;
}
.children {
display: flex;
justify-content: center;
position: relative;
margin-top: 45px;
}
.children::before {
content: '';
height: 25px;
border: 0.00001rem solid #000;
position: absolute;
top: -46px;
}
.child-node {
position: relative;
margin-left: 10px;
margin-right: 10px;
}
.child-node::before {
content: '';
position: absolute;
top: -20px;
left: 50%;
transform: translateX(-50%);
height: 20px;
border-left: 1px solid #000;
}
.children::after {
content: '';
position: absolute;
top: -20px;
left: 0;
right: 0;
border-top: 1px solid #000;
width: v-bind(childrenWidth);
margin-left: v-bind(childrenMarginLeft);
}
</style>
<template>
<div class="tree-node">
<TreeNodeView v-bind="nodeViewConfig"></TreeNodeView>
</div>
</template>
<script setup>
import TreeNodeView from "./components/TreeNodeView.vue";
const nodeViewConfig = {
rootNodeName: '根节点',
childNodes: [
{id: 1, name: '节点1-1'},
{id: 2, name: '节点222222221-2'},
{id: 3, name: '节点1-3'},
{id: 4, name: '节点1-4222222'},
{id: 5, name: '节点1-4'},
{id: 6, name: '节点1-4'}
]
}
</script>
<style scoped>
</style>