Skip to content

Commit dc6030b

Browse files
Liugq5713PanJiaChen
authored andcommitted
perf[Tree-Table]: refactor tree-table (PanJiaChen#1587)
1 parent fc9e724 commit dc6030b

File tree

8 files changed

+558
-393
lines changed

8 files changed

+558
-393
lines changed

src/components/TreeTable/eval.js

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,48 @@
1-
/**
2-
* @Author: jianglei
3-
* @Date: 2017-10-12 12:06:49
4-
*/
5-
'use strict'
61
import Vue from 'vue'
7-
export default function treeToArray(data, expandAll, parent = null, level = null) {
2+
3+
// Flattened array
4+
export default function treeToArray(data, children = 'children') {
85
let tmp = []
9-
Array.from(data).forEach(function(record) {
10-
if (record._expanded === undefined) {
11-
Vue.set(record, '_expanded', expandAll)
6+
data.forEach((item, index) => {
7+
Vue.set(item, '_index', index)
8+
tmp.push(item)
9+
if (item[children] && item[children].length > 0) {
10+
const res = treeToArray(item[children], children)
11+
tmp = tmp.concat(res)
1212
}
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)
13+
})
14+
return tmp
15+
}
16+
17+
export function addAttrs(data, { parent = null, preIndex = false, level = 0, expand = false, children = 'children', show = true, select = false } = {}) {
18+
data.forEach((item, index) => {
19+
const _id = (preIndex ? `${preIndex}-${index}` : index) + ''
20+
Vue.set(item, '_id', _id)
21+
Vue.set(item, '_level', level)
22+
Vue.set(item, '_expand', expand)
23+
Vue.set(item, '_parent', parent)
24+
Vue.set(item, '_show', show)
25+
Vue.set(item, '_select', select)
26+
if (item[children] && item[children].length > 0) {
27+
addAttrs(item[children], {
28+
parent: item,
29+
level: level + 1,
30+
expand,
31+
preIndex: _id,
32+
children,
33+
status,
34+
select
35+
})
2136
}
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)
37+
})
38+
}
39+
40+
export function cleanParentAttr(data, children = 'children') {
41+
data.forEach(item => {
42+
item._parent = null
43+
if (item[children] && item[children].length > 0) {
44+
addAttrs(item[children], children)
2645
}
2746
})
28-
return tmp
47+
return data
2948
}

src/components/TreeTable/index.vue

Lines changed: 139 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,127 +1,177 @@
11
<template>
2-
<el-table :data="formatData" :row-style="showRow" v-bind="$attrs">
3-
<el-table-column v-if="columns.length===0" width="150">
2+
<el-table :data="tableData" :row-style="showRow" v-bind="$attrs" v-on="$listeners" >
3+
<slot name="selection" />
4+
<slot name="pre-column" />
5+
<el-table-column
6+
v-for="item in columns"
7+
:label="item.label"
8+
:key="item.key"
9+
:width="item.width"
10+
:align="item.align||'center'"
11+
:header-align="item.headerAlign">
412
<template slot-scope="scope">
5-
<span v-for="space in scope.row._level" :key="space" class="ms-tree-space"/>
6-
<span v-if="iconShow(0,scope.row)" class="tree-ctrl" @click="toggleExpanded(scope.$index)">
7-
<i v-if="!scope.row._expanded" class="el-icon-plus"/>
8-
<i v-else class="el-icon-minus"/>
9-
</span>
10-
{{ scope.$index }}
13+
<slot :scope="scope" :name="item.key">
14+
<template v-if="item.expand">
15+
<span :style="{'padding-left':+scope.row._level*indent + 'px'} "/>
16+
<span v-show="showSperadIcon(scope.row)" class="tree-ctrl" @click="toggleExpanded(scope.$index)">
17+
<i v-if="!scope.row._expand" class="el-icon-plus" />
18+
<i v-else class="el-icon-minus" />
19+
</span>
20+
</template>
21+
<template v-if="item.checkbox">
22+
<el-checkbox
23+
v-if="scope.row[defaultChildren]&&scope.row[defaultChildren].length>0"
24+
:style="{'padding-left':+scope.row._level*indent + 'px'} "
25+
:indeterminate="scope.row._select"
26+
v-model="scope.row._select"
27+
@change="handleCheckAllChange(scope.row)" />
28+
<el-checkbox
29+
v-else
30+
:style="{'padding-left':+scope.row._level*indent + 'px'} "
31+
v-model="scope.row._select"
32+
@change="handleCheckAllChange(scope.row)" />
33+
</template>
34+
{{ scope.row[item.key] }}
35+
</slot>
1136
</template>
1237
</el-table-column>
13-
<el-table-column v-for="(column, index) in columns" v-else :key="column.value" :label="column.text" :width="column.width">
14-
<template slot-scope="scope">
15-
<!-- Todo -->
16-
<!-- eslint-disable-next-line vue/no-confusing-v-for-v-if -->
17-
<span v-for="space in scope.row._level" v-if="index === 0" :key="space" class="ms-tree-space"/>
18-
<span v-if="iconShow(index,scope.row)" class="tree-ctrl" @click="toggleExpanded(scope.$index)">
19-
<i v-if="!scope.row._expanded" class="el-icon-plus"/>
20-
<i v-else class="el-icon-minus"/>
21-
</span>
22-
{{ scope.row[column.value] }}
23-
</template>
24-
</el-table-column>
25-
<slot/>
2638
</el-table>
2739
</template>
2840

2941
<script>
30-
/**
31-
Auth: Lei.j1ang
32-
Created: 2018/1/19-13:59
33-
*/
34-
import treeToArray from './eval'
42+
import treeToArray, { addAttrs } from './eval.js'
43+
3544
export default {
3645
name: 'TreeTable',
3746
props: {
38-
/* eslint-disable */
3947
data: {
40-
type: [Array, Object],
41-
required: true
48+
type: Array,
49+
required: true,
50+
default: () => []
4251
},
4352
columns: {
4453
type: Array,
4554
default: () => []
4655
},
47-
evalFunc: Function,
48-
evalArgs: Array,
49-
expandAll: {
56+
defaultExpandAll: {
5057
type: Boolean,
5158
default: false
59+
},
60+
defaultChildren: {
61+
type: String,
62+
default: 'children'
63+
},
64+
indent: {
65+
type: Number,
66+
default: 50
67+
}
68+
},
69+
data() {
70+
return {
71+
guard: 1
5272
}
5373
},
5474
computed: {
55-
// 格式化数据源
56-
formatData: function() {
57-
let tmp
58-
if (!Array.isArray(this.data)) {
59-
tmp = [this.data]
60-
} else {
61-
tmp = this.data
75+
children() {
76+
return this.defaultChildren
77+
},
78+
tableData() {
79+
const data = this.data
80+
if (this.data.length === 0) {
81+
return []
6282
}
63-
const func = this.evalFunc || treeToArray
64-
const args = this.evalArgs ? Array.concat([tmp, this.expandAll], this.evalArgs) : [tmp, this.expandAll]
65-
return func.apply(null, args)
83+
addAttrs(data, {
84+
expand: this.defaultExpandAll,
85+
children: this.defaultChildren
86+
})
87+
88+
const retval = treeToArray(data, this.defaultChildren)
89+
return retval
6690
}
6791
},
6892
methods: {
69-
showRow: function(row) {
70-
const show = (row.row.parent ? (row.row.parent._expanded && row.row.parent._show) : true)
71-
row.row._show = show
72-
return show ? 'animation:treeTableShow 1s;-webkit-animation:treeTableShow 1s;' : 'display:none;'
93+
addBrother(row, data) {
94+
if (row._parent) {
95+
row._parent.children.push(data)
96+
} else {
97+
this.data.push(data)
98+
}
7399
},
74-
// 切换下级是否展开
75-
toggleExpanded: function(trIndex) {
76-
const record = this.formatData[trIndex]
77-
record._expanded = !record._expanded
100+
addChild(row, data) {
101+
if (!row.children) {
102+
this.$set(row, 'children', [])
103+
}
104+
row.children.push(data)
78105
},
79-
// 图标显示
80-
iconShow(index, record) {
81-
return (index === 0 && record.children && record.children.length > 0)
106+
delete(row) {
107+
const { _index, _parent } = row
108+
if (_parent) {
109+
_parent.children.splice(_index, 1)
110+
} else {
111+
this.data.splice(_index, 1)
112+
}
113+
},
114+
getData() {
115+
return this.tableData
116+
},
117+
showRow: function({ row }) {
118+
const parent = row._parent
119+
const show = parent ? parent._expand && parent._show : true
120+
row._show = show
121+
return show
122+
? 'animation:treeTableShow 1s;-webkit-animation:treeTableShow 1s;'
123+
: 'display:none;'
124+
},
125+
showSperadIcon(record) {
126+
return record[this.children] && record[this.children].length > 0
127+
},
128+
toggleExpanded(trIndex) {
129+
const record = this.tableData[trIndex]
130+
const expand = !record._expand
131+
record._expand = expand
132+
},
133+
handleCheckAllChange(row) {
134+
this.selcetRecursion(row, row._select, this.defaultChildren)
135+
this.isIndeterminate = row._select
136+
},
137+
selcetRecursion(row, select, children = 'children') {
138+
if (select) {
139+
this.$set(row, '_expand', true)
140+
this.$set(row, '_show', true)
141+
}
142+
const sub_item = row[children]
143+
if (sub_item && sub_item.length > 0) {
144+
sub_item.map(child => {
145+
child._select = select
146+
this.selcetRecursion(child, select, children)
147+
})
148+
}
82149
}
83150
}
84151
}
85152
</script>
86-
<style rel="stylesheet/css">
87-
@keyframes treeTableShow {
88-
from {opacity: 0;}
89-
to {opacity: 1;}
90-
}
91-
@-webkit-keyframes treeTableShow {
92-
from {opacity: 0;}
93-
to {opacity: 1;}
94-
}
95-
</style>
96153

97-
<style lang="scss" rel="stylesheet/scss" scoped>
98-
$color-blue: #2196F3;
99-
$space-width: 18px;
100-
.ms-tree-space {
101-
position: relative;
102-
top: 1px;
103-
display: inline-block;
104-
font-style: normal;
105-
font-weight: 400;
106-
line-height: 1;
107-
width: $space-width;
108-
height: 14px;
109-
&::before {
110-
content: ""
111-
}
154+
<style>
155+
@keyframes treeTableShow {
156+
from {
157+
opacity: 0;
158+
}
159+
to {
160+
opacity: 1;
112161
}
113-
.processContainer{
114-
width: 100%;
115-
height: 100%;
162+
}
163+
@-webkit-keyframes treeTableShow {
164+
from {
165+
opacity: 0;
116166
}
117-
table td {
118-
line-height: 26px;
167+
to {
168+
opacity: 1;
119169
}
170+
}
120171
121-
.tree-ctrl{
122-
position: relative;
123-
cursor: pointer;
124-
color: $color-blue;
125-
margin-left: -$space-width;
126-
}
172+
.tree-ctrl {
173+
position: relative;
174+
cursor: pointer;
175+
color: #2196f3;
176+
}
127177
</style>

0 commit comments

Comments
 (0)