树表格的实现
有时候我们会遇到表格树的展示,类似于下图的需求:
其中组件的封装主要在table-tree文件夹内:
main.vue的内容如下:
1 <template> 2 <el-table :data="formatData" 3 :stripe="option.stripe" 4 :row-style="showRow" 5 :row-class-name="rowClassName" 6 v-bind="$attrs" 7 :border="border"> 8 <el-table-column v-if="columns.length===0" 9 width="150"> 10 <template slot-scope="scope"> 11 <span v-for="space in scope.row._level" 12 class="ms-tree-space" 13 :key="space"></span> 14 <span class="tree-ctrl" 15 v-if="iconShow(0,scope.row)" 16 @click="toggleExpanded(scope.$index)"> 17 <i v-if="!scope.row._expanded" 18 class="el-icon-plus"></i> 19 <i v-else 20 class="el-icon-minus"></i> 21 </span> 22 {{scope.$index}} 23 </template> 24 </el-table-column> 25 <el-table-column v-else 26 v-for="(column, index) in columns" 27 :key="column.value" 28 :label="column.text" 29 :width="column.width"> 30 <template slot-scope="scope"> 31 <span v-if="index === 0" 32 v-for="space in scope.row._level" 33 class="ms-tree-space" 34 :key="space"></span> 35 <span class="tree-ctrl" 36 v-if="iconShow(index,scope.row)" 37 @click="toggleExpanded(scope.$index)"> 38 <i v-if="!scope.row._expanded" 39 class="el-icon-plus"></i> 40 <i v-else 41 class="el-icon-minus"></i> 42 </span> 43 {{scope.row[column.value]}} 44 </template> 45 </el-table-column> 46 <slot></slot> 47 </el-table> 48 </template> 49 50 <script> 51 import treeToArray from "./eval"; 52 export default { 53 name: "AvueTreeTable", 54 props: { 55 option: { 56 type: Object, 57 required: true 58 }, 59 rowClassName: Function, 60 evalFunc: Function, 61 evalArgs: Array 62 }, 63 data() { 64 return {}; 65 }, 66 created() {}, 67 computed: { 68 data: function() { 69 return this.option.data || []; 70 }, 71 columns: function() { 72 return this.option.columns || []; 73 }, 74 expandAll: function() { 75 return this.option.expandAll; 76 }, 77 border: function() { 78 return this.option.border || true; 79 }, 80 // 格式化数据源 81 formatData: function() { 82 let tmp; 83 if (!Array.isArray(this.data)) { 84 tmp = [this.data]; 85 } else { 86 tmp = this.data; 87 } 88 const func = this.evalFunc || treeToArray; 89 const args = this.evalArgs 90 ? Array.concat([tmp, this.expandAll], this.evalArgs) 91 : [tmp, this.expandAll]; 92 return func.apply(null, args); 93 } 94 }, 95 methods: { 96 showRow: function(row) { 97 const show = row.row.parent 98 ? row.row.parent._expanded && row.row.parent._show 99 : true; 100 row.row._show = show; 101 return show 102 ? "animation:treeTableShow 1s;-webkit-animation:treeTableShow 1s;" 103 : "display:none;"; 104 }, 105 // 切换下级是否展开 106 toggleExpanded: function(trIndex) { 107 const record = this.formatData[trIndex]; 108 record._expanded = !record._expanded; 109 }, 110 // 图标显示 111 iconShow(index, record) { 112 return index === 0 && record.children && record.children.length > 0; 113 } 114 } 115 }; 116 </script> 117 <style rel="stylesheet/css"> 118 @keyframes treeTableShow { 119 from { 120 opacity: 0; 121 } 122 to { 123 opacity: 1; 124 } 125 } 126 @-webkit-keyframes treeTableShow { 127 from { 128 opacity: 0; 129 } 130 to { 131 opacity: 1; 132 } 133 } 134 </style> 135 136 <style lang="scss" rel="stylesheet/scss" scoped> 137 $color-blue: #2196f3; 138 $space-width: 18px; 139 .ms-tree-space { 140 position: relative; 141 top: 1px; 142 display: inline-block; 143 font-style: normal; 144 font-weight: 400; 145 line-height: 1; 146 width: $space-width; 147 height: 14px; 148 &::before { 149 content: ""; 150 } 151 } 152 .processContainer { 153 width: 100%; 154 height: 100%; 155 } 156 table td { 157 line-height: 26px; 158 } 159 160 .tree-ctrl { 161 position: relative; 162 cursor: pointer; 163 color: $color-blue; 164 margin-left: -$space-width; 165 } 166 </style>
eval.js的内容如下:
1 /** 2 * @Author: jianglei 3 * @Date: 2017-10-12 12:06:49 4 */ 5 'use strict' 6 import Vue from 'vue' 7 export default function treeToArray(data, expandAll, parent = null, level = null) { 8 let tmp = [] 9 Array.from(data).forEach(function(record) { 10 if (record._expanded === undefined) { 11 Vue.set(record, '_expanded', expandAll) 12 } 13 let _level = 1 14 if (level !== undefined && level !== null) { 15 _level = level + 1 16 } 17 Vue.set(record, '_level', _level) 18 // 如果有父元素 19 if (parent) { 20 Vue.set(record, 'parent', parent) 21 } 22 tmp.push(record) 23 if (record.children && record.children.length > 0) { 24 const children = treeToArray(record.children, expandAll, record, _level) 25 tmp = tmp.concat(children) 26 } 27 }) 28 return tmp 29 }
index.js的内容如下:
1 import TableTree from './src/main'; 2 3 /* istanbul ignore next */ 4 TableTree.install = function(Vue) { 5 Vue.component(TableTree.name, TableTree); 6 }; 7 8 export default TableTree;
在其他组件内只需要引入main.vue即可,
js中option变量为:
1 option: { 2 expandAll: true, 3 columns: [ 4 { 5 text: '事件', 6 value: 'event', 7 width: 200 8 }, 9 { 10 text: 'ID', 11 value: 'id' 12 }, 13 { 14 text: '时间线', 15 value: 'timeLine' 16 }, 17 { 18 text: '备注', 19 value: 'comment' 20 } 21 ], 22 data: [ 23 { 24 id: 0, 25 event: '事件1', 26 timeLine: 50, 27 comment: '无' 28 }, 29 { 30 id: 1, 31 event: '事件1', 32 timeLine: 100, 33 comment: '无', 34 children: [ 35 { 36 id: 2, 37 event: '事件2', 38 timeLine: 10, 39 comment: '无' 40 }, 41 { 42 id: 3, 43 event: '事件3', 44 timeLine: 90, 45 comment: '无', 46 children: [ 47 { 48 id: 4, 49 event: '事件4', 50 timeLine: 5, 51 comment: '无' 52 }, 53 { 54 id: 5, 55 event: '事件5', 56 timeLine: 10, 57 comment: '无' 58 }, 59 { 60 id: 6, 61 event: '事件6', 62 timeLine: 75, 63 comment: '无', 64 children: [ 65 { 66 id: 7, 67 event: '事件7', 68 timeLine: 50, 69 comment: '无', 70 children: [ 71 { 72 id: 71, 73 event: '事件71', 74 timeLine: 25, 75 comment: 'xx' 76 }, 77 { 78 id: 72, 79 event: '事件72', 80 timeLine: 5, 81 comment: 'xx' 82 }, 83 { 84 id: 73, 85 event: '事件73', 86 timeLine: 20, 87 comment: 'xx' 88 } 89 ] 90 }, 91 { 92 id: 8, 93 event: '事件8', 94 timeLine: 25, 95 comment: '无' 96 } 97 ] 98 } 99 ] 100 } 101 ] 102 } 103 ] 104 }
哈哈哈,这样就实现了表格树
但是有时候我们要自定义表格的列,如下图:
实现方式如下(底层封装组件不变,只是在引用的组件内做些改变即可):
1 <tree-table :option="option"> 2 <el-table-column label="事件"> 3 <template slot-scope="scope"> 4 <span style="color:sandybrown">{{scope.row.event}}</span> 5 <el-tag>{{scope.row.timeLine+'ms'}}</el-tag> 6 </template> 7 </el-table-column> 8 <el-table-column label="时间线"> 9 <template slot-scope="scope"> 10 <el-tooltip effect="dark" 11 :content="scope.row.timeLine+'ms'" 12 placement="left"> 13 <div class="processContainer"> 14 <div class="process" 15 :style="{ width:scope.row._width * 500+'px', 16 background:scope.row._width>0.5?'rgba(233,0,0,.5)':'rgba(0,0,233,0.5)', 17 marginLeft:scope.row._marginLeft * 500+'px' }"> 18 <span style="display:inline-block"></span> 19 </div> 20 </div> 21 </el-tooltip> 22 </template> 23 </el-table-column> 24 <el-table-column label="操作" 25 width="200"> 26 <template slot-scope="scope"> 27 <el-button type="text" 28 @click="message(scope.row)">点击</el-button> 29 </template> 30 </el-table-column> 31 <tree-table>
1 option: { 2 data: { 3 id: 1, 4 event: '事件1', 5 timeLine: 100, 6 comment: '无', 7 children: [ 8 { 9 id: 2, 10 event: '事件2', 11 timeLine: 10, 12 comment: '无' 13 }, 14 { 15 id: 3, 16 event: '事件3', 17 timeLine: 90, 18 comment: '无', 19 children: [ 20 { 21 id: 4, 22 event: '事件4', 23 timeLine: 5, 24 comment: '无' 25 }, 26 { 27 id: 5, 28 event: '事件5', 29 timeLine: 10, 30 comment: '无' 31 }, 32 { 33 id: 6, 34 event: '事件6', 35 timeLine: 75, 36 comment: '无', 37 children: [ 38 { 39 id: 7, 40 event: '事件7', 41 timeLine: 50, 42 comment: '无', 43 children: [ 44 { 45 id: 71, 46 event: '事件71', 47 timeLine: 25, 48 comment: 'xx' 49 }, 50 { 51 id: 72, 52 event: '事件72', 53 timeLine: 5, 54 comment: 'xx' 55 }, 56 { 57 id: 73, 58 event: '事件73', 59 timeLine: 20, 60 comment: 'xx' 61 } 62 ] 63 }, 64 { 65 id: 8, 66 event: '事件8', 67 timeLine: 25, 68 comment: '无' 69 } 70 ] 71 } 72 ] 73 } 74 ] 75 } 76 }