CSS: проблема с линиями, соединяющими узлы дерева
Я работаю над рисованием линий, соединяющих узлы дерева, мне удалось этого добиться более или менее, но есть некоторые оборванные линии и т. д., от которых я хочу избавиться.
Вот реализация codepen:- https://codepen.io/Dinesh443/pen/wvWjJeB
Я пытаюсь избавиться от соединительной линии перед корневым узлом, а также от других висячих линий после последнего узла, как показано ниже.
Хотя код написан на Vue js, это простое рекурсивное древовидное представление с использованием тегов 'ul' и 'li'. Я использовал:: до,:: после. селектор psuedo для достижения этой цели.
HTML:-
<div class="container">
<h4>Vue.js Expandable Tree Menu<br/><small>(Recursive Components)</small></h4>
<div id="app">
<tree-menu
:nodes="tree.nodes"
:depth="0"
:label="tree.label"
></tree-menu>
</div>
</div>
<script type="text/x-template" id="tree-menu">
<div class="tree-menu">
<li>
<div class="label-wrapper" @click="toggleChildren">
<div :class="labelClasses">
<i v-if="nodes" class="fa" :class="iconClasses"></i>
{{ label }}
</div>
</div>
<ul>
<tree-menu
v-if="showChildren"
v-for="node in nodes"
:nodes="node.nodes"
:label="node.label"
:depth="depth + 1"
>
</ul>
</tree-menu>
</li>
</div>
</script>
CSS:
body {
font-family: "Open Sans", sans-serif;
font-size: 18px;
font-weight: 300;
line-height: 1em;
}
.container {
width: 300px;
margin: 0 auto;
}
.tree-menu {
.label-wrapper {
padding-bottom: 10px;
margin-bottom: 10px;
// border-bottom: 1px solid #ccc;
.has-children {
cursor: pointer;
}
}
}
.tree-menu li {
list-style-type: none;
margin:5px;
position: relative;
}
.tree-menu li>ul::before {
content: "";
position: absolute;
top:-7px;
left:-30px;
border-left: 1px solid #ccc;
border-bottom:1px solid #ccc;
border-radius:0 0 0 0px;
// width:20px;
height:100%;
}
.tree-menu li>ul::after {
content:"";
display: block;
position:absolute;
top:8px;
left:-30px;
border-left: 1px solid #ccc;
border-top:1px solid #ccc;
border-radius:0px 0 0 0;
width:20px;
height:100%;
}
JavaScript( Vue ):
let tree = {
label: 'root',
nodes: [
{
label: 'item1',
nodes: [
{
label: 'item1.1'
},
{
label: 'item1.2',
nodes: [
{
label: 'item1.2.1'
}
]
}
]
},
{
label: 'item2'
}
]
}
Vue.component('tree-menu', {
template: '#tree-menu',
props: [ 'nodes', 'label', 'depth' ],
data() {
return {
showChildren: false
}
},
computed: {
iconClasses() {
return {
'fa-plus-square-o': !this.showChildren,
'fa-minus-square-o': this.showChildren
}
},
labelClasses() {
return { 'has-children': this.nodes }
},
// indent() {
// return { transform: `translate(${this.depth * 50}px)` }
// }
},
methods: {
toggleChildren() {
this.showChildren = !this.showChildren;
}
}
});
new Vue({
el: '#app',
data: {
tree
}
})
Ответы - CSS: проблема с линиями, соединяющими узлы дерева / CSS: Issue with Lines Connecting Tree Nodes

11.11.2020 04:57:21
У меня есть несколько иной подход к решению Вашего вопроса.
// modified data from array
var data = {
id: 1,
name: '',
open: true, // default open
children: [{
name: 'B',
open: true,
children: [{
name: 'BC1',
open: true,
children: [{
name: 'BC1-S',
open: true,
children: [{
name: 'BC1-1'
},
{
name: 'BC1-2'
}
]
}]
},{
name: 'BC2',
open: true,
children: [{
name: 'BC2-S',
open: true,
children: [{
name: 'BC2-1'
},
{
name: 'BC2-2'
}
]
}]
}]
},
{
name: 'G',
children: [{
name: 'GC1',
children: [{
name: 'GC1-S1',
children: [{
name: 'GC1-1'
},
{
name: 'GC1-2'
}
]
},{
name: 'GC1-S2',
children: [{
name: 'GC1-3'
},
{
name: 'GC1-4'
}
]
}]
}]
}
]
}
// define the item component
Vue.component('item', {
template: '#item-template',
props: {
model: Object
},
data: function() {
return {
open: this.model.open
}
},
computed: {
isFolder: function() {
return this.model.children &&
this.model.children.length
}
},
methods: {
toggle: function() {
if (this.isFolder) {
this.open = !this.open
}
}
}
})
new Vue({
el: '#main',
data: {
treeData: data
}
})
body {
font-family: Menlo, Consolas, monospace;
color: #444;
}
.tree-view {}
.tree-view>ul {
padding-left: 16px;
}
.tree-view li {
list-style-type: none;
margin: 0;
padding: 10px 5px 0;
position: relative;
}
.tree-view li:last-child {
margin-bottom: 10px;
}
.tree-view li::after,
.tree-view li::before {
content: '';
left: -30px;
position: absolute;
right: auto;
}
.tree-view li::before {
border-left: 1px solid #405567;
height: calc(100% + 10px);
top: 0;
width: 1px;
}
.tree-view li::after {
border-top: 1px solid #405567;
height: 20px;
top: 20px;
width: 35px;
}
.tree-view .item {
border: 1px solid #405567;
border-radius: 2px;
background-color: #fff;
display: inline-block;
padding: 2px 6px;
text-decoration: none;
cursor: pointer;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
}
.tree-view .folder {
background-color: #fff;
}
.tree-view>ul>li::after,
.tree-view>ul>li::before {
border: 0;
}
.tree-view li:last-child::before {
height: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script type="text/x-template" id="item-template">
<li>
<div class="item" :class="{folder: isFolder}" @click="toggle">
<span v-if="isFolder">{{ open ? '-' : '+' }}</span> {{ model.name }}
</div>
<ul v-show="open" v-if="isFolder">
<item v-for="(model, index) in model.children" :key="index" :model="model">
</item>
</ul>
</li>
</script>
<div class="tree-view" id="main">
<ul>
<item :model="treeData">
</item>
</ul>
</div>

17.11.2020 06:14:23
Это тот результат, который вы ищете?
ваши "висячие линии" - это просто неправильно рассчитанная высота элемента :before.
.tree-menu-1st-example ul {
padding-left: 0px;
}
.tree-menu-1st-example ul li {
list-style-type: none;
padding-left: 30px;
position: relative;
line-height: 2em;
}
.tree-menu-1st-example ul li:before {
content: "";
position: absolute;
top: 0px;
left: 0px;
border-right: 1px solid #ccc;
border-bottom: 1px solid #ccc;
border-radius: 0 0 0 0px;
height: 100%;
}
.tree-menu-1st-example ul li:after {
content: "";
display: block;
position: absolute;
top: 1em;
left: 0px;
border-top: 1px solid #ccc;
border-radius: 0px 0 0 0;
width: 20px;
height: 100%;
}
.tree-menu-1st-example ul li:last-of-type:before {
height: 1em;
}
/* new example: */
.tree-menu-2 ul {
padding-left: 0px;
}
.tree-menu-2 ul li {
list-style-type: none;
padding-left: 30px;
position: relative;
line-height: 2em;
}
.tree-menu-2 ul .tree-menu-2{
position:relative;
}
.tree-menu-2 ul .tree-menu-2:before {
content: "";
position: absolute;
top: 0px;
left: 0px;
border-right: 1px solid #ccc;
border-bottom: 1px solid #ccc;
border-radius: 0 0 0 0px;
height: 100%;
}
.tree-menu-2 ul li:after {
content: "";
display: block;
position: absolute;
top: 1em;
left: 0px;
border-top: 1px solid #ccc;
border-radius: 0px 0 0 0;
width: 20px;
height: 100%;
}
.tree-menu-2 ul .tree-menu-2:last-of-type:before {
height: 1em;
}
<div class="tree-menu-1st-example">
<ul>
<li>
Root
<ul>
<li>
Item1
<ul>
<li>item 1.1</li>
<li>item 1.1</li>
</ul>
</li>
<li>
Item2
<ul>
<li>item 1.1</li>
<li>item 1.1</li>
</ul>
</li>
<ul>
</li>
</ul>
</div>
<div id="app">
<div class="tree-menu-2">
<li>
<div class="label-wrapper">
<div class="has-children"><i class="fa fa-plus-square-o"></i>
root
</div>
</div>
<ul>
<div class="tree-menu-2">
<li>
<div class="label-wrapper">
<div class="has-children"><i class="fa fa-plus-square-o"></i>
item1
</div>
</div>
<ul>
<div class="tree-menu-2">
<li>
<div class="label-wrapper">
<div class="">
<!---->
item1.1
</div>
</div>
<ul></ul>
</li>
</div>
<div class="tree-menu-2">
<li>
<div class="label-wrapper">
<div class="has-children"><i class="fa fa-plus-square-o"></i>
item1.2
</div>
</div>
<ul>
<div class="tree-menu-2">
<li>
<div class="label-wrapper">
<div class="">
<!---->
item1.2.1
</div>
</div>
<ul></ul>
</li>
</div>
</ul>
</li>
</div>
</ul>
</li>
</div>
<div class="tree-menu-2">
<li>
<div class="label-wrapper">
<div class="">
<!---->
item2
</div>
</div>
<ul></ul>
</li>
</div>
</ul>
</li>
</div>
</div>