Skip to content

Commit aa8f7a5

Browse files
committed
Update table-tree component
1 parent b02477e commit aa8f7a5

File tree

4 files changed

+140
-63
lines changed

4 files changed

+140
-63
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
# Table-Tree
2-
基于 element-ui CSS样式设计的 `Table-Tree` 组件。开放访问 `TableStore`方法,自定义扩展,自定义渲染。
2+
基于 element-ui CSS样式设计的 `Table-Tree` 组件。
33

44

55
## Feature
6+
0. 开放访问 `TableStore`方法,可自定义扩展,自定义渲染。代码更少,性能更强。
67
1. 通过 column 每一列自定义 `render` 函数 + `TableStore` 暴露的各种方法来操作 table 的数据源 实现各种功能,解决了 element-ui 一列仅支持特定的几个 type 展示的问题。
78
2. 通过 Vue 实例的 computed 对象属性 tableData 返回 `TableStore.state.data`,解决了*组件数据源更新*导致*组件状态被更新*的问题。
89
3. 支持特定的expand Depth,渲染指定深度的属性接口。
@@ -123,7 +124,7 @@ const columns = [{
123124
```
124125

125126
- className
126-
- style
127+
- styleStr
127128
- header, 顶部元素
128129
- footer, 底部元素
129130
- expandDepth: number, 指定默认渲染的树的递归深度

example/App.vue

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
title="table-tree"
88
desc="推荐使用"
99
:good="[`columns 完全定制化`, `完全重写 el-table`]"
10-
:bad="[`需要学习额外的 TableStore API`]"
10+
:bad="[`需要学习几个额外的 TableStore API`]"
1111
>
1212
<table-tree
1313
v-loading="tableLoading"
@@ -27,7 +27,6 @@
2727
<desc-pannel
2828
title="table-tree-depth"
2929
desc="Use element-ui `Table` component and render itself recursively."
30-
:good="[`递归扩展,代码量少,可定制性高`, `支持自定义扩展、渲染深度,自定义渲染 table-column 'render'`]"
3130
>
3231
<table-tree-depth
3332
v-loading="tableLoading"
@@ -48,8 +47,6 @@
4847
<desc-pannel
4948
title="table-tree-recursive"
5049
desc="Use element-ui `Table` component and write itself recursively."
51-
:good="[`可定制性高`, `table-column type可根据不同深度定制` ]"
52-
:bad="[`非递归扩展,代码量多`, `table-column 不支持自定义 cell render`]"
5350
>
5451
<table-tree-recursive
5552
class="tree-table-view"

src/components/TableTree/index.js

Lines changed: 21 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import TableStore from "./store";
1+
import TableStore, { geneFlattenArrayFromTreeByDepth } from "./store";
22

33
const TableTree = {
44
name: "VCTableTree",
55
componentName: "VCTableTree",
66
props: {
77
// ...ElTable.props,
88
className: [String, Object],
9-
styleStr: {
9+
style: {
1010
type: String,
1111
default: "width: 100%"
1212
},
@@ -56,18 +56,18 @@ const TableTree = {
5656
type: Number,
5757
default: 10
5858
}, */
59-
expandDepth: {/* Expand Depth */
59+
expandDepth: {/* Expand Depth */
6060
type: Number,
6161
default: 1
6262
},
63-
expandRowKeys: {/* Expand Row Keys */
63+
expandRows: {/* Expand Rows */
6464
type: Array,
6565
default() {
6666
return [];
6767
}
6868
},
6969
// Selection
70-
selectedRowsKeys: {/* Selection Row Keys */
70+
selectRows: {/* Select Rows */
7171
type: Array,
7272
default() {
7373
return []
@@ -76,17 +76,17 @@ const TableTree = {
7676
},
7777

7878
data() {
79-
const store = new TableStore({
79+
const store = new TableStore(this, {
8080
data: this.dataSource,
8181
columns: this.columns,
8282
rowKey: this.rowKey,
8383
expandDepth: this.expandDepth,
84-
expandRowKeys: this.expandRowKeys,
85-
selectedRowsKeys: this.selectedRowsKeys,
84+
expandRows: this.expandRows,
85+
selectRows: this.selectRows,
8686
});
8787

8888
return {
89-
store
89+
store,
9090
};
9191
},
9292

@@ -102,26 +102,6 @@ const TableTree = {
102102
} */
103103
}
104104
},
105-
106-
/* expandDepth: {
107-
immediate: true,
108-
handler(value) {
109-
if (value) {``
110-
const expandRows = geneExpandRows(this, this.store.data, value)
111-
// const expandRowsKeys = geneExpandRows.call(this, this.store.data, value)
112-
this.store.setState({ expandRows });
113-
}
114-
}
115-
}, */
116-
117-
expandRowKeys: {
118-
immediate: true,
119-
handler(value) {
120-
if (value) {
121-
this.store.setState({ expandRowKeys: value });
122-
}
123-
}
124-
}
125105
},
126106

127107
computed: {
@@ -152,9 +132,11 @@ const TableTree = {
152132
} = this;
153133

154134
return (
155-
<div class="table-tree">
135+
<div class={["table-tree", this.className]} style={this.style}>
156136
{header}
157137
<table
138+
width={this.width}
139+
height={this.height}
158140
class={[
159141
"el-table",
160142
{
@@ -169,7 +151,7 @@ const TableTree = {
169151
>
170152
{ this.renderColgroup() }
171153
{showHeader && this.renderHeader()}
172-
<tbody>{this.renderBody(this.tableData)}</tbody>
154+
<tbody>{this.renderTableRows(this.tableData)}</tbody>
173155
</table>
174156
{footer}
175157
</div>
@@ -202,9 +184,9 @@ const TableTree = {
202184
border="0"
203185
>
204186
<tr class="el-table__row">
205-
{tableColumns.map(({ prop, label, key }) => (
187+
{tableColumns.map(({ prop, label = '', key = '' }) => (
206188
<th
207-
key={label || prop || key}
189+
key={[label, prop, key].join(':')}
208190
colspan="1"
209191
rowspan="1"
210192
class="is-leaf"
@@ -217,7 +199,7 @@ const TableTree = {
217199
);
218200
},
219201

220-
renderBody(tableData, depth = 0) {
202+
renderTableRows(tableData, depth = 0) {
221203
const { rowKey = "", rowClassName } = this;
222204

223205
return tableData.map((row, index) => {
@@ -236,19 +218,19 @@ const TableTree = {
236218
key={row[rowKey] || index}
237219
class={classNames}
238220
>
239-
{this.renderColumn(row, index, depth)}
221+
{this.renderDataCells(row, index, depth)}
240222
</tr>,
241223
this.store.isRowExpanded(row) &&
242-
this.renderBody(row.children, depth + 1)
224+
this.renderTableRows(row.children, depth + 1)
243225
]
244226
})
245227
},
246228

247-
renderColumn(row, rowIndex, depth = 0) {
229+
renderDataCells(row, rowIndex, depth = 0) {
248230
const { tableColumns = [], rowKey = "" } = this;
249231

250232
return tableColumns.map((column, columnIndex) => {
251-
const { prop, key, render, /* width, minWidth, */ } = column;
233+
const { prop, render, /* width, minWidth, */ } = column;
252234
const cell =
253235
typeof render === 'function' &&
254236
render(this.$createElement /* alias for h */, {
@@ -262,7 +244,7 @@ const TableTree = {
262244
});
263245

264246
return (
265-
<td key={row[rowKey] || key} rowspan="1" colspan="1">
247+
<td rowspan="1" colspan="1">
266248
<div class="cell">{cell || row[prop] || ''}</div>
267249
</td>
268250
);

src/components/TableTree/store.js

Lines changed: 115 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,37 @@ const toggleRowExpansion = function(state, row, expanded) {
2828
return changed;
2929
};
3030

31+
const toggleRowSelection = function(state, row, selected) {
32+
let changed = false;
33+
const selectRows = state.selectRows;
34+
35+
if (typeof selected !== "undefined") {
36+
const index = selectRows.indexOf(row);
37+
if (selected) {
38+
if (index === -1) {
39+
selectRows.push(row);
40+
changed = true;
41+
}
42+
} else {
43+
if (index !== -1) {
44+
selectRows.splice(index, 1);
45+
changed = true;
46+
}
47+
}
48+
} else {
49+
const index = selectRows.indexOf(row);
50+
if (index === -1) {
51+
selectRows.push(row);
52+
changed = true;
53+
} else {
54+
selectRows.splice(index, 1);
55+
changed = true;
56+
}
57+
}
58+
59+
return changed;
60+
};
61+
3162
const getKeysMap = function(array, rowKey) {
3263
const arrayMap = {};
3364
(array || []).forEach((row, index) => {
@@ -36,7 +67,7 @@ const getKeysMap = function(array, rowKey) {
3667
return arrayMap;
3768
};
3869

39-
const getRowIdentity = (row, rowKey) => {
70+
const getRowIdentity = function (row, rowKey){
4071
if (!row) throw new Error("row is required when get row identity");
4172
if (typeof rowKey === "string") {
4273
if (rowKey.indexOf(".") < 0) {
@@ -53,18 +84,43 @@ const getRowIdentity = (row, rowKey) => {
5384
}
5485
};
5586

87+
export const geneFlattenArrayFromTreeByDepth = (
88+
tree,
89+
maxDepth,
90+
currDepth = 0,
91+
res = []
92+
) => {
93+
let i = 0;
94+
let item = null;
95+
const l = tree.length;
96+
97+
if (currDepth >= maxDepth) return (currDepth = 0) || []
98+
99+
for(; i < l; i++) {
100+
item = tree[i]
101+
res[res.length] = item
102+
103+
if (item && item.children && item.children.length) {
104+
geneFlattenArrayFromTreeByDepth(item.children, maxDepth, currDepth + 1, res)
105+
}
106+
}
107+
108+
return res;
109+
};
56110

57111
export default class TableState {
58-
constructor(initialState) {
112+
constructor(table, initialState) {
113+
this.table = table;
59114
this.states = {
60115
data: null,
61116
columns: "",
62117
rowKey: "",
63-
selectedRowsKeys: [],
118+
selectRows: [],
64119
expandRows: [],
65-
expandRowKeys: [],
120+
expandDepth: 0,
66121
defaultExpandAll: false,
67122
};
123+
// console.log(this.states)
68124
this.setState(initialState);
69125
}
70126

@@ -83,11 +139,28 @@ export default class TableState {
83139
/* 切换当前行展开收起状态 */
84140
toggleRowExpansion(row, expanded) {
85141
const changed = toggleRowExpansion(this.states, row, expanded);
142+
86143
if (changed) {
87-
// eslint-disable-next-line
88-
console.log('toggleRowExpansion has changed')
89-
// this.table.$emit("expand-change", row, this.states.expandRows);
90-
// this.scheduleLayout();
144+
this.table.$emit("expand-change", row, this.states.expandRows);
145+
}
146+
}
147+
148+
isRowSelected(row) {
149+
const { selectRows = [], rowKey } = this.states;
150+
151+
if (rowKey) {
152+
const expandMap = getKeysMap(selectRows, rowKey);
153+
return !!expandMap[getRowIdentity(row, rowKey)];
154+
}
155+
156+
return selectRows.indexOf(row) !== -1;
157+
}
158+
159+
toggleRowSelection(row, selected) {
160+
const changed = toggleRowSelection(this.states, row, selected);
161+
162+
if (changed) {
163+
this.table.$emit("select-change", row, this.states.selectRows);
91164
}
92165
}
93166

@@ -106,21 +179,29 @@ export default class TableState {
106179
}
107180
}
108181

109-
_setData(state, data) {
182+
_setData(states, data) {
110183
// eslint-disable-next-line
111-
const dataInstanceChanged = state._data !== data;
112-
state._data = data;
113-
state.data = data;
114-
115-
const rowKey = state.rowKey;
116-
const defaultExpandAll = state.defaultExpandAll;
117-
if (defaultExpandAll) {
118-
this.states.expandRows = (state.data || []).slice(0);
184+
const dataInstanceChanged = states._data !== data;
185+
states._data = data;
186+
states.data = data;
187+
188+
const rowKey = states.rowKey;
189+
const expandDepth = states.expandDepth;
190+
const defaultExpandAll = states.defaultExpandAll;
191+
192+
// keep expand rows
193+
if (defaultExpandAll) { /* Does not support this attribute */
194+
this.states.expandRows = (states.data || []).slice(0);
195+
} else if (expandDepth) {
196+
this.states.expandRows = geneFlattenArrayFromTreeByDepth(
197+
(states.data || []),
198+
expandDepth,
199+
).slice(0)
119200
} else if (rowKey) {
120201
// update expandRows to new rows according to rowKey
121202
const ids = getKeysMap(this.states.expandRows, rowKey);
122203
let expandRows = [];
123-
for (const row of state.data) {
204+
for (const row of states.data) {
124205
const rowId = getRowIdentity(row, rowKey);
125206

126207
if (ids[rowId]) {
@@ -133,7 +214,23 @@ export default class TableState {
133214
// clear the old rows
134215
this.states.expandRows = [];
135216
}
217+
/*
218+
// const selectRows = states.selectRows
219+
if (this.selectRows && this.selectRows.length) {
220+
const ids = getKeysMap(this.states.selectRows, rowKey);
221+
let selectRows = []
222+
for (const row of states.data) {
223+
const rowId = getRowIdentity(row, rowKey);
136224
225+
if (ids[rowId]) {
226+
expandRows.push(row);
227+
}
228+
}
229+
230+
// The slice() method returns a shallow copy of a portion of an array into a new array object selected from begin to end (end not included).
231+
this.states.selectRows = selectRows
232+
}
233+
*/
137234
// Vue.nextTick(() => this.table.updateScrollY());
138235
}
139236
}

0 commit comments

Comments
 (0)