特殊需求,必须要做个树形结构图,好不容易做出来了,小有成就感,希望给有需要的人。
组件内容,放在component文件夹里的组件(路径src>component>TreeView>index.vue):
<template>
<div :class="['tree-node', levelClass]">
<div
class="node-content"
@click="toggle"
:class="{ noChildren: !node.children || !node.children.length }"
>
<span v-if="hasChildren" class="toggle-icon">
<span class="icon-text">{{ isOpen ? '-' : '+' }}</span>
</span>
<div class="node-text">{{ node.topic }}</div>
</div>
<div v-if="isOpen && hasChildren" class="children-container">
<div class="vertical-line"></div>
<div class="children">
<tree-view
v-for="child in node.children"
:key="child.id"
:node="child"
:level="level + 1"
></tree-view>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'TreeView',
props: {
node: Object,
level: {
type: Number,
default: 1
}
},
data() {
return {
isOpen: true // 默认展开
};
},
computed: {
hasChildren() {
return this.node.children && this.node.children.length;
},
levelClass() {
return `level-${(this.level - 1) % 5 + 1}`;
}
},
methods: {
toggle() {
if (this.hasChildren) {
this.isOpen = !this.isOpen;
}
}
}
};
</script>
<style scoped>
.tree-node {
position: relative;
margin: 10px 0;
padding-left: 20px;
}
.node-content {
cursor: pointer;
display: flex;
align-items: center;
padding: 10px 15px;
border-radius: 8px;
transition: background-color 0.3s ease, border-color 0.3s ease, box-shadow 0.3s ease;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
position: relative;
}
.node-content:hover {
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.2);
}
.node-content.noChildren {
cursor: default;
}
.toggle-icon {
display: flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
margin-right: 10px;
border-radius: 50%;
transition: background-color 0.3s ease, transform 0.3s ease;
flex-shrink: 0;
line-height: 1;
font-size: 14px;
}
.node-text {
flex-grow: 1;
}
.children-container {
position: relative;
margin-left: 20px;
padding-left: 10px;
}
.vertical-line {
position: absolute;
top: 0;
left: -20px;
width: 2px;
height: 100%;
}
.children {
position: relative;
padding-left: 10px;
}
.children::before {
content: '';
position: absolute;
top: 50%;
left: -10px;
width: 10px;
height: 2px;
}
/* Level 1 */
.level-1 .node-content {
background-color: #e0f7fa;
border: 2px solid #80deea;
color: #006064;
}
.level-1 .node-content:hover {
background-color: #b2ebf2;
border-color: #4dd0e1;
}
.level-1 .toggle-icon {
background-color: #80deea;
border: 2px solid #006064;
color: #006064;
}
.level-1 .toggle-icon:hover {
background-color: #4dd0e1;
}
.level-1 .vertical-line,
.level-1 .children::before {
background-color: #80deea;
}
/* Level 2 */
.level-2 .node-content {
background-color: #f8bbd0;
border: 2px solid #f48fb1;
color: #880e4f;
}
.level-2 .node-content:hover {
background-color: #f48fb1;
border-color: #f06292;
}
.level-2 .toggle-icon {
background-color: #f48fb1;
border: 2px solid #880e4f;
color: #880e4f;
}
.level-2 .toggle-icon:hover {
background-color: #f06292;
}
.level-2 .vertical-line,
.level-2 .children::before {
background-color: #f48fb1;
}
/* Level 3 */
.level-3 .node-content {
background-color: #dcedc8;
border: 2px solid #aed581;
color: #33691e;
}
.level-3 .node-content:hover {
background-color: #aed581;
border-color: #8bc34a;
}
.level-3 .toggle-icon {
background-color: #aed581;
border: 2px solid #33691e;
color: #33691e;
}
.level-3 .toggle-icon:hover {
background-color: #8bc34a;
}
.level-3 .vertical-line,
.level-3 .children::before {
background-color: #aed581;
}
/* Level 4 */
.level-4 .node-content {
background-color: #fff9c4;
border: 2px solid #fff176;
color: #f57f17;
}
.level-4 .node-content:hover {
background-color: #fff176;
border-color: #ffee58;
}
.level-4 .toggle-icon {
background-color: #fff176;
border: 2px solid #f57f17;
color: #f57f17;
}
.level-4 .toggle-icon:hover {
background-color: #ffee58;
}
.level-4 .vertical-line,
.level-4 .children::before {
background-color: #fff176;
}
/* Level 5 */
.level-5 .node-content {
background-color: #d1c4e9;
border: 2px solid #9575cd;
color: #311b92;
}
.level-5 .node-content:hover {
background-color: #9575cd;
border-color: #7e57c2;
}
.level-5 .toggle-icon {
background-color: #9575cd;
border: 2px solid #311b92;
color: #311b92;
}
.level-5 .toggle-icon:hover {
background-color: #7e57c2;
}
.level-5 .vertical-line,
.level-5 .children::before {
background-color: #9575cd;
}
</style>
页面里引用
<div class="treeBox">
<tree-view :node="treeViewData"></tree-view>
</div>
import TreeView from '@/components/TreeView';
components: {
TreeView
},
data(){
treeViewData: {
topic: '根节点',
id: 1,
children: [{
topic: '一级节点1',
id: 2,
children: [{
topic: '二级节点1-1',
id: 3,
children: [{
topic: '三级节点1-1-1',
id: 4,
children: [{
topic: '四级节点1-1-1-1',
id: 5,
children: [{
topic: '五级节点1-1-1-1-1',
id: 6
},
{
topic: '五级节点1-1-1-1-2',
id: 7
}
]
},
{
topic: '四级节点1-1-1-2',
id: 8
}
]
},
{
topic: '三级节点1-1-2',
id: 9
}
]
},
{
topic: '二级节点1-2',
id: 10,
children: [{
topic: '三级节点1-2-1',
id: 11
}]
}
]
},
{
topic: '一级节点2',
id: 12,
children: [{
topic: '二级节点2-1',
id: 13
}]
}
]
},
}
效果如下