1. 程式人生 > 其它 >橫向結構的樹元件(leader-line-vue)

橫向結構的樹元件(leader-line-vue)

近期做專案時需要做一個橫向的樹結構的圖,如下所示:

本圖的實現採用了leader-line-vue元件,

具體實現如下:

先npm installleader-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