【问题标题】:CSS: Issue with Lines Connecting Tree NodesCSS:连接树节点的线问题
【发布时间】:2021-02-14 11:03:02
【问题描述】:

我正在画一条连接树节点的线,我或多或少地实现了它,但是我想摆脱一些悬空线等。

这里是 codepen 的实现:- https://codepen.io/Dinesh443/pen/wvWjJeB

我正在尝试摆脱根节点之前的连接线以及最后一个节点之后的其他悬空线,如下所示。

虽然代码是用 Vue js 编写的,但它是一个使用 'ul' 和 'li' 标签的简单递归树表示。我用过::before,::after。伪选择器来实现这一点。

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
  }
})

【问题讨论】:

  • 我仍然坚持这一点,我能够使用 not:first-child 属性摆脱根节点之前的行,但其余的悬空线仍然可用。跨度>

标签: javascript html css vue.js sass


【解决方案1】:

这是您要寻找的结果吗?

您的“悬空线”只是错误地计算了 :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>

【讨论】:

  • 感谢您的回复,这里的问题是我的组件是递归的。为了您的方便,我已经准备好在数据转换为 li 和 ul 标签并将您的 css 应用到它之后 HTML 的外观。这是代码笔:-codepen.io/Dinesh443/pen/vYKPbVx。由于这种递归,html 看起来有点混乱。但现在就是这样。请你看一下。
  • 我已根据您的 html 输出更新了 css。 Root 可能需要额外的样式,但您应该明白这一点。请注意,我在元素的父级之前进行了更改,并赋予了该父级的相对位置。但主要是 :last-of-type:before 解决了你的悬空线问题。
  • 希望你记住这个问题。我遇到了线路溢出的问题。我已经复制了 html 并创建了这个 jsbin 复制器。 JS Bin Reproducer 。在某些时候,线条仍然溢出。你可以在这里看到我的实现图像Image Of My implementation,我刚刚复制了我的 vue 代码在 js bin 中生成的 li 和 ul 标签以及 CSS 。此处的任何输入将不胜感激。谢谢!如果您有任何问题,请告诉我。
【解决方案2】:

我有一些不同的方法来解决你的问题。

// 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>

【讨论】:

  • 感谢您提供替代解决方案。但是我对现有代码笔的实现如此深入,以至于我不确定是否可以将其更改为您的方法。有没有什么办法可以改变现有的代码笔以理智的方式加入这些行?谢谢!
  • 至少我想知道我的实现出了什么问题以及为什么会出现这些额外的行。如果您能弄清楚,那将非常有帮助。再次非常感谢您。
猜你喜欢
  • 2011-04-11
  • 2020-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-13
  • 2018-04-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多