美文网首页VUE实践记录
vue横向组织结构图实现

vue横向组织结构图实现

作者: Year_h | 来源:发表于2020-07-22 17:20 被阅读0次

    实现效果图如下:


    image.png

    数据格式 tree

    let  dataInfo = [
            {
              name: "root",
              value: "root",
              children: [
                {
                  name: "child1",
                  value: "一级1",
                  children: [
                    {
                      name: "child2",
                      value: "二级1",
                      children: []
                    },
                    {
                      name: "child2",
                      value: "二级2",
                      children: []
                    }
                  ]
                },
                {
                  name: "child1",
                  value: "一级2",
                  children: [
                    {
                      name: "child2",
                      value: "二级3",
                      children: [
                      ]
                    }
                  ]
                }
              ]
            }
          ]
    

    实现代码 递归调用最小实现单元 组件NodeTree.vue

    <!--
     * @Descripttion: 横向树实现demo
     * @version: 
     * @Author: year
    --> 
    <template>
      <div class="item-content" ref="cardItemDiv">
        <div class="info-card">
          <div class="card-item" v-for="(item, index) in data" :key="index">
            <span
              class="vertical-line"
              :style="computedHeight(item.height, data.length, index)"
              v-if="item.name !== 'root'"
            ></span>
            <span class="horizontal-line" v-if="item.name !== 'root'"></span>
            <div class="div-card">
              <div>{{item.value}}</div>
            </div>
            <span class="horizontal-line" v-if="item.children&&item.children.length !== 0"></span>
            <equip-list :data="item.children" v-if="item.children&&item.children.length !== 0"></equip-list>
          </div>
        </div>
      </div>
    </template>
    
    <script>
    export default {
      name: "equipList",
      props: {
        data: Array
      },
      data() {
        return {
        };
      },
      methods: {
        computedHeight(pheight, length, index) {
          if (length == 1 || length == 0) {
            return {
              height: "0px",
              display: "none"
            };
          } else {
            let height = 0;
            let marginTop = 0;
            let marginB = 0;
            if (index == 0) {
              height = pheight / 2;
              marginTop = height;
              return {
                height: height + "px",
                "margin-top": marginTop + "px"
              };
            }
            if (index == length - 1) {
              height = pheight / 2;
              marginB = height;
              return {
                height: height + "px",
                "margin-bottom": marginB + "px"
              };
            } else {
              height = pheight;
              return {
                height: height + "px"
              };
            }
          }
        }
      },
      components: {},
      mounted() {
      }
    };
    </script>
    
    <style lang='scss' scoped>
    .item-content {
      height: 100%;
      width: 100%;
      display: flex;
      .vertical-line {
        display: inline-block;
        width: 2px;
        background: #eaeaea;
      }
    
      .card-item {
        display: flex;
        align-items: center;
        .horizontal-line {
          width: 40px;
          display: inline-block;
          height: 2px;
          background: #eaeaea;
        }
      }
    }
    
    .div-card {
      height: 77px;
      & > div {
        display: flex;
        justify-content: center;
        align-items: center;
        width: 220px;
        height: 67px;
        background: inherit;
        background-color: rgba(253, 253, 253, 1);
        border: none;
        border-radius: 4px;
        -moz-box-shadow: 1px 3px 5px rgba(0, 0, 0, 0.2);
        -webkit-box-shadow: 1px 3px 5px rgba(0, 0, 0, 0.2);
        box-shadow: 1px 3px 5px rgba(0, 0, 0, 0.2);
        color: #8d8d8e;
      }
    }
    </style>
    
    

    父组件调用 Parent.vue

    引入NodeTree.vue

    <!--
     * @Descripttion: 横向组织架构图实现
     * @version: 
     * @Author: year
    
    --> 
    <template>
      <div class="shopping-table-info">
        <NodeTree :data="dataInfo" />
      </div>
    </template>
    
    <script>
    import NodeTree from "./ShoppingEquipList";
    export default {
      data() {
        return {
          dataInfo: []
        };
      },
      methods: {
        getDataInfo() {
          let dataInfo = [
            {
              name: "root",
              value: "root",
              children: [
                {
                  name: "child1",
                  value: "一级1",
                  children: [
                    {
                      name: "child2",
                      value: "二级1",
                      children: []
                    },
                    {
                      name: "child2",
                      value: "二级2",
                      children: []
                    }
                  ]
                },
                {
                  name: "child1",
                  value: "一级2",
                  children: [
                    {
                      name: "child2",
                      value: "二级3",
                      children: []
                    }
                  ]
                }
              ]
            }
          ];
    
          let fixedData = dataInfo.map(item => {
            return this.traveTree(item);
          });
    
          this.dataInfo = fixedData;
        },
        traveTree(nodeInfo) {
          let childrenInfo = nodeInfo.children;
          if (!childrenInfo || childrenInfo.length == 0) {
            nodeInfo.height = 77;
          } else {
            childrenInfo.map(item => {
              this.traveTree(item);
            });
    
            nodeInfo.height = childrenInfo.reduce((preV, n) => {
              return preV + n.height;
            }, 0);
          }
          return nodeInfo;
        }
      },
      components: {
        NodeTree
      },
      mounted() {
        this.getDataInfo();
      }
    };
    </script>
    
    
    
    

    实现思路

    抽取最小实现单元,然后循环递归即可


    image.png

    (1)左右两端水平线 实现:


    image.png
     <span class="horizontal-line" v-if="item.name !== 'root'"></span>
    <span class="horizontal-line"  v-if="item.children&&item.children.length !== 0"></span>
    

    span标签画两条水平线,然后利用flex布局,居中布局即可。最小单元后面的水平线判断没有后代的时候 不显示即可
    (2)连接后代的纵轴部分实现:


    image.png

    需要知道每个后代的高度,然后第一个后代的高度/2 + 中间所有后代的高度和+ 最后一个后代的高度/2 就是所需要纵轴的高度
    高度的具体实现代码: 假设最后一层后代的高度为70
    a.初始数据处理: 利用二叉树的 后序遍历方法先给每一个节点添加上高度属性

         traveTree(nodeInfo) {
          let childrenInfo = nodeInfo.children;
          if (!childrenInfo || childrenInfo.length == 0) {
            nodeInfo.height = 77;
          } else {
            childrenInfo.map(item => {
              this.traveTree(item);
            });
    
            nodeInfo.height = childrenInfo.reduce((preV, n) => {
              return preV + n.height;
            }, 0);
          }
          return nodeInfo;
        }
    

    b.计算链接线高度

     computedHeight(pheight, length, index) {
          if (length == 1 || length == 0) {
            return {
              height: "0px",
              display: "none"
            };
          } else {
            let height = 0;
            let marginTop = 0;
            let marginB = 0;
            if (index == 0) {
              height = pheight / 2;
              marginTop = height;
              return {
                height: height + "px",
                "margin-top": marginTop + "px"
              };
            }
            if (index == length - 1) {
              height = pheight / 2;
              marginB = height;
              return {
                height: height + "px",
                "margin-bottom": marginB + "px"
              };
            } else {
              height = pheight;
              return {
                height: height + "px"
              };
            }
          }
        }
    

    相关文章

      网友评论

        本文标题:vue横向组织结构图实现

        本文链接:https://www.haomeiwen.com/subject/nsazkktx.html