zoukankan      html  css  js  c++  java
  • 前端vue2-org-tree实现精美组织架构图

      最近遇到开发组织架构的需求,与以往开发的组织架构不同,不光要展示人名,还要显示职务(或者子公司名称)、对应的头像等,并且要考虑,如果用户未上传头像,需使用默认头像(男、女、中性),(⊙o⊙)…要尊重尊重,不能随便喊那啥...,还要考虑子公司或者不同部门之间的员工借调问题,现简化效果图如下:

    最终实现效果图如下:

    纵向(默认展开前3级):

    横向(默认展开前3级,因为截图无法全屏的问题,部分第3级未展开):

      废话不多说,说方法:采用vue2-org-tree组件来实现效果。

    npm

    1 # use npm
    2 npm i vue2-org-tree
    3 # use yarn 4 yarn add vue2-org-tree

    安装 loader

    npm install --save-dev less less-loader(不安装less-loader基本上都会报错)

    Import Plugins(main.js引入)  (CDN方式请自行测试)

    import Vue2OrgTree from 'vue2-org-tree'
     
    Vue.use(Vue2OrgTree)
     
    由于测试过程当中,发生的版本兼容问题(加载css样式丢失),故将CSS样式统一放到样式文件中引入,样式文件如下:
      1 @colors:#1FAAEB;
      2 .org-tree-container {
      3   display: inline-block;
      4   padding: 15px;
      5   background-color: #fff;
      6 }
      7 
      8 .org-tree {
      9   // display: inline-block;
     10   display: table;
     11   text-align: center;
     12 
     13   &:before, &:after {
     14     content: '';
     15     display: table;
     16   }
     17 
     18   &:after {
     19     clear: both;
     20   }
     21 }
     22 
     23 .org-tree-node,
     24 .org-tree-node-children {
     25   position: relative;
     26   margin: 0;
     27   padding: 0;
     28   list-style-type: none;
     29 
     30   &:before, &:after {
     31     transition: all .35s;
     32   }
     33 }
     34 .org-tree-node-label {
     35   position: relative;
     36   display: inline-block;
     37 
     38   .org-tree-node-label-inner {
     39     padding: 10px 15px;
     40     text-align: center;
     41     border-radius: 3px;
     42     box-shadow: 0 1px 5px rgba(0, 0, 0, .15);
     43   }
     44 }
     45 .org-tree-node-btn {
     46   position: absolute;
     47   top: 100%;
     48   left: 50%;
     49   width: 20px;
     50   height: 20px;
     51   z-index: 10;
     52   margin-left: -11px;
     53   margin-top: 9px;
     54   background-color: #fff;
     55   border: 1px solid @colors;
     56   border-radius: 50%;
     57   box-shadow: 0 0 2px rgba(0, 0, 0, .15);
     58   cursor: pointer;
     59   transition: all .35s ease;
     60 
     61   &:hover {
     62     background-color: #e7e8e9;
     63     transform: scale(1.15);
     64   }
     65 
     66   &:before, &:after {
     67     content: '';
     68     position: absolute;
     69   }
     70 
     71   &:before {
     72     top: 50%;
     73     left: 4px;
     74     right: 4px;
     75     height: 0;
     76     border-top: 1px solid @colors;
     77   }
     78 
     79   &:after {
     80     top: 4px;
     81     left: 50%;
     82     bottom: 4px;
     83     width: 0;
     84     border-left: 1px solid @colors;
     85   }
     86 
     87   &.expanded:after {
     88     border: none;
     89   }
     90 }
     91 .org-tree-node {
     92   padding-top: 20px;
     93   display: table-cell;
     94   vertical-align: top;
     95 
     96   &.is-leaf, &.collapsed {
     97     padding-left: 10px;
     98     padding-right: 10px;
     99   }
    100 
    101   &:before, &:after {
    102     content: '';
    103     position: absolute;
    104     top: 0;
    105     left: 0;
    106     width: 50%;
    107     height: 19px;
    108   }
    109 
    110   &:after {
    111     left: 50%;
    112     border-left: 1px solid @colors;
    113   }
    114 
    115   &:not(:first-child):before,
    116   &:not(:last-child):after {
    117     border-top: 1px solid @colors;
    118   }
    119 
    120 }
    121 .collapsable .org-tree-node.collapsed {
    122   padding-bottom: 30px;
    123 
    124   .org-tree-node-label:after {
    125     content: '';
    126     position: absolute;
    127     top: 100%;
    128     left: 0;
    129     width: 50%;
    130     height: 20px;
    131     border-right: 1px solid @colors;
    132   }
    133 }
    134 .org-tree > .org-tree-node {
    135   padding-top: 0;
    136 
    137   &:after {
    138     border-left: 0;
    139   }
    140 }
    141 .org-tree-node-children {
    142   padding-top: 20px;
    143   display: table;
    144 
    145   &:before {
    146     content: '';
    147     position: absolute;
    148     top: 0;
    149     left: 0;
    150     width: 50%;
    151     height: 20px;
    152     border-right: 1px solid @colors;
    153     border-left: none;
    154   }
    155 
    156   &:after {
    157     content: '';
    158     display: table;
    159     clear: both;
    160   }
    161 }
    162 
    163 .horizontal {
    164   .org-tree-node {
    165     // display: flex;
    166     // flex-direction: row;
    167     // justify-content: flex-start;
    168     // align-items: center;
    169     display: table-cell;
    170     float: none;
    171     padding-top: 0;
    172     padding-left: 20px;
    173 
    174     &.is-leaf, &.collapsed {
    175       padding-top: 10px;
    176       padding-bottom: 10px;
    177     }
    178 
    179     &:before, &:after {
    180       width: 19px;
    181       height: 50%;
    182     }
    183 
    184     &:after {
    185       top: 50%;
    186       left: 0;
    187       border-left: 0;
    188     }
    189 
    190     &:only-child:before {
    191       top: 1px;
    192       border-bottom: 1px solid @colors;
    193     }
    194 
    195     &:not(:first-child):before,
    196     &:not(:last-child):after {
    197       border-top: 0;
    198       border-left: 1px solid @colors;
    199     }
    200 
    201     &:not(:only-child):after {
    202       border-top: 1px solid @colors;
    203     }
    204 
    205     .org-tree-node-inner {
    206       display: table;
    207     }
    208 
    209   }
    210 
    211   .org-tree-node-label {
    212     display: table-cell;
    213     vertical-align: middle;
    214   }
    215 
    216   &.collapsable .org-tree-node.collapsed {
    217     padding-right: 30px;
    218 
    219     .org-tree-node-label:after {
    220       top: 0;
    221       left: 100%;
    222       width: 20px;
    223       height: 50%;
    224       border-right: 0;
    225       border-bottom: 1px solid @colors;
    226     }
    227   }
    228 
    229   .org-tree-node-btn {
    230     top: 50%;
    231     left: 100%;
    232     margin-top: -11px;
    233     margin-left: 9px;
    234   }
    235 
    236   & > .org-tree-node:only-child:before {
    237     border-bottom: 0;
    238   }
    239 
    240   .org-tree-node-children {
    241     // display: flex;
    242     // flex-direction: column;
    243     // justify-content: center;
    244     // align-items: flex-start;
    245     display: table-cell;
    246     padding-top: 0;
    247     padding-left: 20px;
    248 
    249     &:before {
    250       top: 50%;
    251       left: 0;
    252       width: 20px;
    253       height: 0;
    254       border-left: 0;
    255       border-top: 1px solid @colors;
    256     }
    257 
    258     &:after {
    259       display: none;
    260     }
    261 
    262     & > .org-tree-node {
    263       display: block;
    264     }
    265   }
    266 }
    View Code

    组件中HTML代码如下:

     1 <template>
     2   <div class="org-boxs">
     3     <vue2-org-tree
     4       name="test"
     5       :data="datas"
     6       :horizontal="horizontal"
     7       :label-class-name="labelClassName"
     8       :render-content="renderContent"
     9       collapsable
    10       @on-expand="onExpand"
    11       @on-node-click="onNodeClick"
    12     />
    13   </div>
    14 </template>
    View Code

    data中定义如下:

      1 data () {
      2       return {
      3         horizontal: false,
      4         collapsable: false,
      5         expandAll: true,
      6         labelClassName: "bg-none",
      7         datas:{
      8           id:'1',
      9           label:'老张伟',
     10           position:'董事长',
     11           img:'https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=4007973853,1345044449&fm=15&gp=0.jpg',
     12           relations:'1',
     13           children:[
     14             {
     15               id:'1-1',
     16               label:'大张嘎',
     17               position:'总经理',
     18               img:'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=629230260,2582796696&fm=26&gp=0.jpg',
     19               relations:'1-1',
     20               children:[
     21                 {
     22                   id:'1-1-1',
     23                   label:'小张嘎',
     24                   position:'策划部',
     25                   img:'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=2495406741,1368429183&fm=26&gp=0.jpg',
     26                   relations:'1-1',
     27                 },
     28                 {
     29                   id:'1-1-2',
     30                   label:'中张嘎',
     31                   position:'规划部',
     32                   img:'https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=4125471676,2511464594&fm=26&gp=0.jpg',
     33                   relations:'1-1',
     34                 },
     35               ]
     36             },
     37             {
     38               id:'1-2',
     39               label:'大刘彪',
     40               position:'秘书长',
     41               img:'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=291861640,4252957999&fm=26&gp=0.jpg',
     42               relations:'1-2',
     43               children:[
     44                 {
     45                   id:'1-2-1',
     46                   label:'中刘彪',
     47                   position:'人事部',
     48                   img:'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=4122062364,793453037&fm=26&gp=0.jpg',
     49                   relations:'1-2',
     50                 },
     51                 {
     52                   id:'1-2-2',
     53                   label:'小刘彪',
     54                   position:'行政部',
     55                   img:'https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=1018449383,841488959&fm=15&gp=0.jpg',
     56                   relations:'1-2',
     57                 },
     58               ]
     59             },
     60             {
     61               id:'1-3',
     62               label:'大美女',
     63               position:'财务总监',
     64               img:'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=2745812195,432411379&fm=26&gp=0.jpg',
     65               relations:'1-3',
     66               children:[
     67                 {
     68                   id:'1-3-1',
     69                   label:'中美女',
     70                   position:'财务部',
     71                   img:'',
     72                   relations:'1-3',
     73                   sex:2,
     74                   children:[
     75                     {
     76                       id:'1-3-1-1',
     77                       label:'小美女',
     78                       position:'财务科',
     79                       img:'',
     80                       sex:0,
     81                       relations:'1-3',
     82                     },
     83                   ]
     84                 },
     85               ]
     86             },
     87             {
     88               id:'1-4',
     89               label:'大霸王',
     90               position:'技术总监',
     91               img:'',
     92               sex:1,
     93               relations:'1-4',
     94               children:[
     95                 {
     96                   id:'1-4-1',
     97                   label:'小霸王',
     98                   position:'技术部',
     99                   img:'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=481633131,466344723&fm=26&gp=0.jpg',
    100                   relations:'1-4',
    101                 },
    102                 {
    103                   id:'1-4-2',
    104                   label:'中霸王',
    105                   position:'研发部',
    106                   img:'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=1490853638,1893546593&fm=26&gp=0.jpg',
    107                   relations:'1-4',
    108                 },
    109               ]
    110             },
    111             {
    112               id:'1-5',
    113               label:'大赵帅',
    114               position:'运营总监',
    115               img:'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2010835987,458488842&fm=15&gp=0.jpg',
    116               relations:'1-5',
    117               children:[
    118                 {
    119                   id:'1-5-1',
    120                   label:'小赵帅',
    121                   position:'市场部',
    122                   img:'https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=3576627708,888952220&fm=26&gp=0.jpg',
    123                   relations:'1-5',
    124                 },
    125                 {
    126                   id:'1-5-2',
    127                   label:'中赵帅',
    128                   position:'销售部',
    129                   img:'https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=3102026869,1790261072&fm=26&gp=0.jpg',
    130                   relations:'1-3',
    131                 },
    132                 {
    133                   id:'1-5-3',
    134                   label:'老赵帅',
    135                   position:'执行部',
    136                   img:'https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=3444708870,1488183897&fm=26&gp=0.jpg',
    137                   relations:'1-5',
    138                 },
    139               ]
    140             },
    141           ],
    142         },
    143         manUrl:require('@/assets/man.jpeg'),
    144         womanUrl:require('@/assets/woman.jpg'),
    145         shemaleUrl:require('@/assets/shemale.jpg'),
    146       }
    147     },
    View Code
    manUrl、womanUrl、shemaleUrl为对应的男、女、中性默认头像,datas中的img为用户上传到服务器的URL,relations默认为各个公司的id(可根据实际情况自行设置),用来判断该人员劳动关系属于哪个公司/部门(尤其是子公司之间的员工借调问题,或者政府部门市县局间的人员借调问题)。
    组件自带方法如下:
     1 onExpand(e, data) {
     2         if ("expand" in data) {
     3           data.expand = !data.expand;
     4           if (!data.expand && data.children) {
     5             this.collapse(data.children);
     6           }
     7         } else {
     8           this.$set(data, "expand", true);
     9         }
    10       },
    11       //点击选项执行的方法,可以用于跳转到其他链接,注意一定要写协议头
    12       onNodeClick(e, data) {
    13         //console.log(data.label);
    14         if(data.url==null){
    15           return false
    16         }else{
    17           window.open(data.url)
    18         }
    19       },
    20       collapse(list) {
    21         var _this = this;
    22         list.forEach(function(child) {
    23           if (child.expand) {
    24             child.expand = false;
    25           }
    26           child.children && _this.collapse(child.children);
    27         });
    28       },
    29       expandChange() {
    30         this.toggleExpand(this.data, this.expandAll);
    31       },
    32       toggleExpand(data, val) {
    33         var _this = this;
    34         if (Array.isArray(data)) {
    35           data.forEach(function(item) {
    36             _this.$set(item, "expand", val);
    37             if (item.children) {
    38               _this.toggleExpand(item.children, val);
    39             }
    40           });
    41         } else {
    42           this.$set(data, "expand", val);
    43           if (data.children) {
    44             _this.toggleExpand(data.children, val);
    45           }
    46         }
    47       }
    View Code

    组件加载时的初始化方法如下(默认展开3级):

    1 initOrg(){
    2         this.$set(this.datas,'expand',true);
    3         if(this.datas.children){
    4           this.datas.children.forEach((item,index)=>{
    5             this.$set(item,'expand',true);
    6           })
    7         }
    8       },
    View Code

    重点来了,每个节点内容的渲染方法如下:

    1 renderContent(h, data) {
    2         return (
    3           <span style="100%;height:100%;display:block;padding:10px 15px;border-radius:3px;" class={data.relations === '1-1'?'bg-tomato':(data.relations === '1-2'?'bg-gold':(data.relations === '1-3'?'bg-gray':(data.relations === '1-4'?'bg-lightpink':(data.relations === '1-5'?'bg-blue':'bg-green'))))}>
    4             <dd style="height:6vh;border-radius:50%;padding:0;margin-bottom:1vh;"><img style="6vh;height:6vh;border-radius:50%;" src={data.img?data.img:(data.sex === 1?this.manUrl:(data.sex === 2?this.womanUrl:this.shemaleUrl))}/></dd>
    5             <dd style="font-size:1.6vh;">{data.label}</dd>
    6             <dd style="font-size:1vh;">{data.position}</dd>
    7           </span>
    8         )
    9       },
    View Code

    CSS样式如下:

     1 <style lang="less">
     2   @import "~@assets/less/org-tree.less";
     3   .org-boxs{
     4     width:100%;
     5     height:100%;
     6     text-align: center;
     7     /*background: #030C24;*/
     8     background-image: -webkit-radial-gradient(ellipse farthest-corner at center 40%, #000d4d 0%, #000105 100%);
     9     background-image: radial-gradient(ellipse farthest-corner at center 40%, #000d4d 0%, #000105 100%);
    10     overflow-y: scroll;
    11   }
    12   .org-tree-container{
    13     background:none!important;
    14   }
    15   .org-tree-node-label {
    16     white-space: nowrap;
    17   }
    18   .bg-none{
    19     background-color:#030C24;
    20     color:#ffffed;
    21   }
    22   .bg-white {
    23      background-color: #ECF5FF;
    24    }
    25   .org-tree-node-label .org-tree-node-label-inner {
    26     width:6vw;
    27     padding: 0px 0px;
    28     text-align: center;
    29     border-radius: 3px;
    30     box-shadow: 0 1px 5px rgba(0, 0, 0, 0.15);
    31    /* border: 1px solid @colors;*/
    32     overflow: hidden;
    33     box-sizing: border-box;
    34   }
    35   .bg-tomato {
    36     background-color: #9E4A1C;
    37   }
    38   .bg-gold {
    39     background-color: #ECA150;
    40   }
    41   .bg-gray {
    42     background-color: #DECEAA;
    43   }
    44   .bg-lightpink {
    45     background-color: lightpink;
    46   }
    47   .bg-blue {
    48     background-color: #057D9F;
    49   }
    50   .bg-green {
    51     background-color: #50CB90;
    52   }
    53 </style>
    View Code

    最终效果如文章开始效果图所示,renderContent方法中渲染节点背景颜色class的判断,有更好的方式的,请联系我,多谢!

    PS:组件封装至此已基本完毕,转载请注明出处

  • 相关阅读:
    SQL 2012 Group By Rollup, Grouping
    SQL 2012 Restore HeaderOnly
    EasyPerformanceCounterHelper
    并发异步处理队列 .NET 4.5+ (改进性能计数器) 2013-11-16
    CodeTimerPerformance EasyPerformanceCounterHelper .NET 4.5
    csc.rsp Nuget MVC/WebAPI 5.0、SignalR 2.0、Rx、Json、Azure、EntityFramework、OAuth、Spatial
    MEF Parts Sample
    免费超高速卡片式病人基本信息列表控件
    微观云计算系列谈之一:基本概念
    golang 无法将Slice类型[]a 转换为 Slice[]b
  • 原文地址:https://www.cnblogs.com/trampeagle/p/13432335.html
Copyright © 2011-2022 走看看