横向结构的树组件(leader-line-vue)

近期做项目时需要做一个横向的树结构的图,如下所示:

 

 本图的实现采用了leader-line-vue组件,

具体实现如下:

先npm install leader-line-vue --save,安装依赖

然后,子组件RightTree的封装,代码如下:

  1 <template>
  2   <div class="TreeRight" id="treeRight" v-if="showTree">
  3     <div class="childs">
  4       <div
  5         class="child"
  6         v-for="(item, index) in list"
  7         :key="item.id + '-child-' + index"
  8       >
  9         <div
 10           class="child-item"
 11           :style="{
 12             marginRight:
 13               item.children && item.children.length > 1 ? '20px' : '',
 14           }"
 15         >
 16           <div class="childname" :id="item">
 17             <div class="content-box" :ref="item.id" :id="item.id">
 18               {{ item.id }}
 19               <p
 20                 v-for="(itemshow, index3) in showfields"
 21                 :key="'itemshow' + index3"
 22               >
 23                 {{ itemshow.name }}{{ item[itemshow.key] }}
 24               </p>
 25             </div>
 26             <div style="width: 30px"></div>
 27             <div
 28               class="position-top"
 29               v-if="isFirst(item.id) && domready"
 30               :style="position_top(item.id, 'top')"
 31             ></div>
 32             <div
 33               class="position-top"
 34               v-if="isLast(item.id)"
 35               :style="position_top(item.id, 'bottom')"
 36             ></div>
 37           </div>
 38           <div style="width: 160px"></div>
 39         </div>
 40         <!-- 递归组件展示子节点 -->
 41         <div
 42           class="child-children"
 43           v-if="item.children && item.children.length"
 44         >
 45           <RightTree :list="item.children" :showfields="showfields" />
 46         </div>
 47       </div>
 48     </div>
 49   </div>
 50 </template>
 51 
 52 <script>
 53 import LeaderLine from "leader-line-vue";
 54 export default {
 55   name: "RightTree",
 56   components: {},
 57   data() {
 58     return {
 59       domready: false,
 60       lines: [],
 61     };
 62   },
 63   created() {},
 64   props: {
 65     list: {
 66       type: Array,
 67       default: () => [],
 68     },
 69     showfields: {
 70       type: Array,
 71       default: () => [],
 72     },
 73   },
 74   mounted() {
 75     this.$nextTick(() => {
 76       this.domready = true;
 77       this.drawArrowLine();
 78     });
 79   },
 80   computed: {
 81     /**
 82      * 是否展示树计算属性
 83      */
 84     showTree() {
 85       return this.list && this.list.length;
 86     },
 87   },
 88   beforeDestroy() {
 89     /**
 90      * 离开页面时销毁所有line
 91      */
 92     if (this.lines && this.lines.length) {
 93       this.lines.forEach((line) => {
 94         line.remove();
 95       });
 96     }
 97   },
 98   methods: {
 99     /**
100      * 递归绘制箭头
101      */
102     drawArrowLine() {
103       this.drawLeaderLine(this.list);
104       document.getElementById("treeRight").addEventListener("scroll", () => {
105       if (this.lines && this.lines.length) {
106         this.lines.forEach((line) => {
107           line.position();
108         });
109       }
110     });
111     },
112     /**
113      * 根据上下级关系绘制线条
114      */
115     drawLeaderLine(list) {
116       list.forEach((element) => {
117         let start = document.getElementById(element.id);
118         if (element.children && element.children.length) {
119           element.children.forEach((child) => {
120             let line = LeaderLine.setLine(
121               start,
122               document.getElementById(child.id)
123             );
124             line.color = "#7F7F7F";
125             line.path = "fluid";
126             line.size = 1;
127             line.setOptions({
128               solid: { animation: true },
129             });
130             this.lines.push(line);
131           });
132           this.drawLeaderLine(element.children);
133         }
134       });
135     },
136     position_top(id, position) {
137       let dom = document.getElementById(id);
138       let height;
139       if (dom) {
140         height = dom.clientHeight;
141       }
142       let rt;
143       if (position === "top") {
144         rt = {
145           height: height / 2 - 2 + "px",
146           top: 0,
147         };
148       }
149       if (position === "bottom") {
150         rt = {
151           height: height / 2 + 1 + "px",
152           bottom: 0,
153         };
154       }
155       return rt;
156     },
157     isFirst(id) {
158       return (
159         this.list.length > 1 && this.list.map((x) => x.id).indexOf(id) === 0
160       );
161     },
162     isLast(id) {
163       return (
164         this.list.length > 1 &&
165         this.list.map((x) => x.id).indexOf(id) === this.list.length - 1
166       );
167     },
168   },
169 };
170 </script>
171 
172 <style lang="scss" scoped>
173 .TreeRight {
174   width: 100%;
175   height: 100%;
176   overflow: auto;
177   p {
178     margin: 0;
179     font-size: 13px;
180   }
181   display: flex;
182   .father {
183     width: 70px;
184     background-color: red;
185     padding: 100px 10px;
186   }
187   .childs {
188     .child {
189       display: flex;
190       background-color: #fff;
191       .child-item {
192         display: flex;
193         align-items: center;
194         margin: 10px 0;
195         .childname {
196           .content-box {
197             text-align: left;
198             border: 1px solid #e8e8e8;
199             padding: 10px;
200             height: 100px;
201             border-radius: 2px;
202             width: 100%;
203             box-shadow: 0 2px 4px 0 rgba(181, 181, 181, 0.7);
204           }
205           cursor: pointer;
206           height: 100%;
207           display: flex;
208           align-items: center;
209           width: 220px;
210           text-align: center;
211           justify-content: center;
212           position: relative;
213           padding: 10px 0;
214           .position-arrow {
215             position: absolute;
216             left: -22px;
217           }
218           .position-top {
219             position: absolute;
220             width: 3px;
221             background-color: #fff;
222             left: -23px;
223             height: 10px;
224           }
225         }
226         .childarrow {
227           height: 100%;
228           display: flex;
229           align-items: center;
230         }
231       }
232     }
233     .child-children {
234       display: flex;
235       flex-direction: column;
236       justify-content: center;
237     }
238   }
239 }
240 </style>
View Code

父亲组件引用方式如下:

 1 <template>
 2   <div>
 3     <right-tree
 4       v-if="list && list.length"
 5       :list="list"
 6       :showfields="showFields"
 7     ></right-tree>
 8   </div>
 9 </template>
10 <script>
11 import RightTree from '../components/RightTree'
12 export default {
13     components:{
14         RightTree,
15     },
16     data(){
17         return{
18             list: [//datasource
19                 {
20                     id: '1',
21                     name: 'span1',
22                     serviceId: 'service1',
23                     children: [
24                         {
25                             id: '1-1',
26                             name: 'user',
27                             serviceId: 'service-user',
28                             children: [
29                                 {
30                                     id: '1-1-1',
31                                     name: 'shop',
32                                     serviceId: '18',
33                                     children: [
34                                         {
35                                             id: '1-1-1-1',
36                                             name: 'common',
37                                             serviceId: 'common-service',
38                                         },
39                                     ],
40                                 },
41                                 {
42                                     id: '1-1-2',
43                                     name: 'account1',
44                                     serviceId: 'account-service',
45                                 },
46                                 {
47                                     id: '1-1-3',
48                                     name: 'account2',
49                                     serviceId: 'account-service',
50 
51                                 },
52                                 {
53                                     id: '1-1-4',
54                                     name: 'account3',
55                                     serviceId: 'account-service',
56                                 },
57                             ],
58                         },
59                         {
60                             id: '1-2',
61                             name: 'truck',
62                             serviceId: 'truck-pay',
63                             work: 'web',
64                         },
65                     ],
66                 },
67             ],
68             showFields: [
69                 {
70                     name: '服务名称:',
71                     key: 'name',
72                 },
73                 {
74                     name: '服务编号:',
75                     key: 'serviceId',
76                 },
77             ],
78         }
79     },
80     methods:{
81 
82     },
83     
84 }
85 </script>
View Code

其实就是用leader-line-vue绘制了引导线,leader-line-vue的功能还是蛮强大的,想了解更深,可以参考官网:https://www.npmjs.com/package/leader-line-vue

posted @ 2021-06-23 10:42  yuwenjing  阅读(2746)  评论(0编辑  收藏  举报