CSS: проблема с линиями, соединяющими узлы дерева


CSS: проблема с линиями, соединяющими узлы дерева

01.11.2020 08:01:59 Просмотров 7 Источник

Я работаю над рисованием линий, соединяющих узлы дерева, мне удалось этого добиться более или менее, но есть некоторые оборванные линии и т. д., от которых я хочу избавиться.

Вот реализация codepen:- https://codepen.io/Dinesh443/pen/wvWjJeB

Я пытаюсь избавиться от соединительной линии перед корневым узлом, а также от других висячих линий после последнего узла, как показано ниже.

enter image description here

Хотя код написан на 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

Bhavin Solanki

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>

Является ответом!
Deividas Cha

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>

Помочь в развитии проекта:
Закрыть X