mirror of
https://gitee.com/ElemeFE/element.git
synced 2024-11-30 11:17:38 +08:00
Update Table:
1. Add rowKey prop for Table. 2. Add clearSelection method for Table. 2. Add reserveSelection prop for TableColumn[type="selection"]
This commit is contained in:
parent
e396db7c91
commit
6ab0d57428
@ -25,6 +25,8 @@
|
||||
|
||||
- 全屏 Loading 现在默认不再锁定屏幕滚动。如果需要的话,可添加 `lock` 修饰符
|
||||
- Table 删除属性 fixedColumnCount, customCriteria, customBackgroundColors
|
||||
- Table 的 allow-no-selection 属性更名为 allow-no-current-row
|
||||
- Table 的 selectionchange、cellmouseenter、cellmouseleave、cellclick 事件更名为 selection-change、cell-mouseenter、cell-mouseleave、cell-click。
|
||||
|
||||
### 1.0.0-rc.7
|
||||
|
||||
|
@ -670,15 +670,15 @@
|
||||
|
||||
选择单行数据时使用色块表示。
|
||||
|
||||
:::demo Table 组件提供了选择的支持,只需要配置`selection-mode`属性即可实现单选(`single`)、多选(`multiple`),如果不需要则设置为`none`。之后由`selectionchange`事件来管理选中时触发的事件,它会传入一个`value`,`value`为生成表格时的对应对象。本例中还使用了`allow-no-selection`属性,它接受一个`Boolean`,若为`true`,则允许为空,默认为`false`,此时将会产生默认值,为填入数组的第一个对象。如果需要显示索引,可以增加一列`el-table-column`,设置`type`属性为`index`即可显示从 1 开始的索引号。
|
||||
:::demo Table 组件提供了选择的支持,只需要配置`selection-mode`属性即可实现单选(`single`)、多选(`multiple`),如果不需要则设置为`none`。之后由`selection-change`事件来管理选中时触发的事件,它会传入一个`value`,`value`为生成表格时的对应对象。本例中还使用了`allow-no-current-row`属性,它接受一个`Boolean`,若为`true`,则允许为空,默认为`false`,此时将会产生默认值,为填入数组的第一个对象。如果需要显示索引,可以增加一列`el-table-column`,设置`type`属性为`index`即可显示从 1 开始的索引号。
|
||||
```html
|
||||
<template>
|
||||
<el-table
|
||||
:data="tableData"
|
||||
selection-mode="single"
|
||||
@selectionchange="handleSelectionChange"
|
||||
@selection-change="handleSelectionChange"
|
||||
style="width: 100%"
|
||||
allow-no-selection>
|
||||
allow-no-current-row>
|
||||
<el-table-column
|
||||
type="index"
|
||||
width="50">
|
||||
@ -739,14 +739,14 @@
|
||||
|
||||
选择多行数据时使用 Checkbox。
|
||||
|
||||
:::demo 除了`selection-mode`的设置外,多选与单选并没有太大差别,只是传入`selectionchange`事件中的参数从对象变成了对象数组。此外,需要提供一个列来显示多选框: 手动添加一个`el-table-column`,设`type`属性为`selection`即可。在本例中,为了方便说明其他属性,我们还使用了`inline-template`和`show-tooltip-when-overflow`:设置了`inline-template`属性后,可以通过调用`row`对象中的值取代`prop`属性的设置;默认情况下若内容过多会折行显示,若需要单行显示可以使用`show-tooltip-when-overflow`属性,它接受一个`Boolean`,为`true`时多余的内容会在 hover 时以 tooltip 的形式显示出来。
|
||||
:::demo 除了`selection-mode`的设置外,多选与单选并没有太大差别,只是传入`selection-change`事件中的参数从对象变成了对象数组。此外,需要提供一个列来显示多选框: 手动添加一个`el-table-column`,设`type`属性为`selection`即可。在本例中,为了方便说明其他属性,我们还使用了`inline-template`和`show-tooltip-when-overflow`:设置了`inline-template`属性后,可以通过调用`row`对象中的值取代`prop`属性的设置;默认情况下若内容过多会折行显示,若需要单行显示可以使用`show-tooltip-when-overflow`属性,它接受一个`Boolean`,为`true`时多余的内容会在 hover 时以 tooltip 的形式显示出来。
|
||||
```html
|
||||
<template>
|
||||
<el-table
|
||||
:data="tableData3"
|
||||
selection-mode="multiple"
|
||||
style="width: 100%"
|
||||
@selectionchange="handleMultipleSelectionChange">
|
||||
@selection-change="handleMultipleSelectionChange">
|
||||
<el-table-column
|
||||
type="selection"
|
||||
width="50">
|
||||
@ -888,17 +888,26 @@
|
||||
| stripe | 是否为斑马纹 table | boolean | — | false |
|
||||
| border | 是否带有纵向边框 | boolean | — | false |
|
||||
| fit | 列的宽度是否自撑开 | boolean | — | true |
|
||||
| rowClassName | 行的 className 的回调,会传入 row, index。 | Function | - | - |
|
||||
| row-class-name | 行的 className 的回调,会传入 row, index。 | Function | - | - |
|
||||
| row-key | 行数据的 Key,用来优化 Table 的渲染;在使用 reserve-selection 功能的情况下,该属性是必填的 | Function, String | - | |
|
||||
| selection-mode | 列表项选择模式 | string | single/multiple/none | none |
|
||||
| allow-no-selection | 单选模式是否允许选项为空 | boolean | — | false |
|
||||
| allow-no-current-row | 单选模式是否允许选项为空 | boolean | — | false |
|
||||
|
||||
### Table Events
|
||||
| 事件名 | 说明 | 参数 |
|
||||
| ---- | ---- | ---- |
|
||||
| selectionchange | 当选择项发生变化时会触发该事件 | selected |
|
||||
| cellmouseenter | 当单元格 hover 进入时会触发该事件 | row, column, cell, event |
|
||||
| cellmouseleave | 当单元格 hover 退出时会触发该事件 | row, column, cell, event |
|
||||
| cellclick | 当某个单元格被点击时会触发该事件 | row, column, cell, event |
|
||||
| select | 当用户手动勾选数据行的 Checkbox 时触发的事件 | selection |
|
||||
| select-all | 当用户手动勾选全选 Checkbox 时触发的事件 | selection |
|
||||
| selection-change | 当选择项发生变化时会触发该事件 | selection |
|
||||
| cell-mouseenter | 当单元格 hover 进入时会触发该事件 | row, column, cell, event |
|
||||
| cell-mouseleave | 当单元格 hover 退出时会触发该事件 | row, column, cell, event |
|
||||
| cell-click | 当某个单元格被点击时会触发该事件 | row, column, cell, event |
|
||||
| row-click | 当某一行被点击时会触发该事件 | row, event |
|
||||
|
||||
### Table Methods
|
||||
| 方法名 | 说明 | 参数 |
|
||||
| ---- | ---- | ---- |
|
||||
| clearSelection | 清空用户的选择,当使用 reserve-selection 功能的时候,可能会需要使用此方法 | selection |
|
||||
|
||||
### Table-column Attributes
|
||||
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
|
||||
@ -914,4 +923,5 @@
|
||||
| show-tooltip-when-overflow | 当过长被隐藏时显示 tooltip | Boolean | — | false |
|
||||
| inline-template | 指定该属性后可以自定义 column 模板,参考多选的时间列,通过 row 获取行信息,JSX 里通过 _self 获取当前上下文。此时不需要配置 prop 属性 | — | — |
|
||||
| align | 对齐方式 | String | left, center, right | left |
|
||||
| selectable | 仅对 type=selection 的列有效,类型为 Function,Function 的返回值用来决定这一行的 CheckBox 是否可以勾选 | Function | - |
|
||||
| selectable | 仅对 type=selection 的列有效,类型为 Function,Function 的返回值用来决定这一行的 CheckBox 是否可以勾选 | Function | - | - |
|
||||
| reserve-selection | 仅对 type=selection 的列有效,类型为 Boolean,为 true 则代表会保留之前数据的选项,需要配合 Table 的 clearSelection 方法使用。 | Boolean | - | false |
|
@ -134,7 +134,7 @@ export default {
|
||||
if (cell) {
|
||||
const column = getColumnByCell(table, cell);
|
||||
const hoverState = table.hoverState = { cell, column, row };
|
||||
table.$emit('cellmouseenter', hoverState.row, hoverState.column, hoverState.cell, event);
|
||||
table.$emit('cell-mouseenter', hoverState.row, hoverState.column, hoverState.cell, event);
|
||||
}
|
||||
|
||||
// 判断是否text-overflow, 如果是就显示tooltip
|
||||
@ -145,12 +145,10 @@ export default {
|
||||
|
||||
handleCellMouseLeave(event) {
|
||||
const cell = getCell(event);
|
||||
if (!cell) return;
|
||||
|
||||
if (cell) {
|
||||
const table = this.$parent;
|
||||
const oldHoverState = table.hoverState;
|
||||
table.$emit('cellmouseleave', oldHoverState.row, oldHoverState.column, oldHoverState.cell, event);
|
||||
}
|
||||
const oldHoverState = this.$parent.hoverState;
|
||||
this.$parent.$emit('cell-mouseleave', oldHoverState.row, oldHoverState.column, oldHoverState.cell, event);
|
||||
},
|
||||
|
||||
handleMouseEnter(index) {
|
||||
@ -164,13 +162,13 @@ export default {
|
||||
if (cell) {
|
||||
const column = getColumnByCell(table, cell);
|
||||
if (column) {
|
||||
table.$emit('cellclick', row, column, cell, event);
|
||||
table.$emit('cell-click', row, column, cell, event);
|
||||
}
|
||||
}
|
||||
|
||||
this.store.commit('setSelectedRow', row);
|
||||
|
||||
table.$emit('rowclick', row, event);
|
||||
table.$emit('row-click', row, event);
|
||||
},
|
||||
|
||||
getCellContent(row, property, columnId) {
|
||||
|
@ -49,7 +49,7 @@ const forced = {
|
||||
headerTemplate: function(h, label) {
|
||||
return <div>{ label || '#' }</div>;
|
||||
},
|
||||
template: function(h, { row, $index }) {
|
||||
template: function(h, { $index }) {
|
||||
return <div>{ $index + 1 }</div>;
|
||||
},
|
||||
sortable: false
|
||||
@ -117,7 +117,8 @@ export default {
|
||||
},
|
||||
fixed: [Boolean, String],
|
||||
formatter: Function,
|
||||
selectable: Function
|
||||
selectable: Function,
|
||||
reserveSelection: Boolean
|
||||
},
|
||||
|
||||
render() {},
|
||||
@ -203,6 +204,7 @@ export default {
|
||||
showTooltipWhenOverflow: this.showTooltipWhenOverflow,
|
||||
formatter: this.formatter,
|
||||
selectable: this.selectable,
|
||||
reserveSelection: this.reserveSelection,
|
||||
fixed: this.fixed
|
||||
});
|
||||
|
||||
|
@ -2,6 +2,15 @@ import Vue from 'vue';
|
||||
import debounce from 'throttle-debounce/debounce';
|
||||
import { orderBy } from './util';
|
||||
|
||||
const getRowIdentity = (row, rowKey) => {
|
||||
if (!row) throw new Error('row is required when get row identity');
|
||||
if (typeof rowKey === 'string') {
|
||||
return row[rowKey];
|
||||
} else if (typeof rowKey === 'function') {
|
||||
return rowKey.call(null, row);
|
||||
}
|
||||
};
|
||||
|
||||
const TableStore = function(table, initialState = {}) {
|
||||
if (!table) {
|
||||
throw new Error('Table is required.');
|
||||
@ -9,6 +18,7 @@ const TableStore = function(table, initialState = {}) {
|
||||
this.table = table;
|
||||
|
||||
this.states = {
|
||||
rowKey: null,
|
||||
_columns: [],
|
||||
columns: [],
|
||||
fixedColumns: [],
|
||||
@ -21,8 +31,9 @@ const TableStore = function(table, initialState = {}) {
|
||||
direction: null
|
||||
},
|
||||
isAllSelected: false,
|
||||
selection: null,
|
||||
allowNoSelection: false,
|
||||
selection: [],
|
||||
reserveSelection: false,
|
||||
allowNoCurrentRow: false,
|
||||
selectionMode: 'none',
|
||||
selectable: null,
|
||||
currentRow: null,
|
||||
@ -43,7 +54,31 @@ TableStore.prototype.mutations = {
|
||||
data.forEach((item) => Vue.set(item, '$selected', false));
|
||||
}
|
||||
states.data = orderBy((data || []), states.sortCondition.property, states.sortCondition.direction);
|
||||
this.updateSelectedRow();
|
||||
this.updateCurrentRow();
|
||||
|
||||
if (!states.reserveSelection) {
|
||||
states.isAllSelected = false;
|
||||
} else {
|
||||
const rowKey = states.rowKey;
|
||||
if (rowKey) {
|
||||
const selectionMap = {};
|
||||
states.selection.forEach((row) => {
|
||||
selectionMap[getRowIdentity(row, rowKey)] = row;
|
||||
});
|
||||
|
||||
states.data.forEach((row) => {
|
||||
const rowId = getRowIdentity(row, rowKey);
|
||||
if (selectionMap[rowId]) {
|
||||
row.$selected = true;
|
||||
selectionMap[rowId] = row;
|
||||
}
|
||||
});
|
||||
|
||||
this.updateAllSelected();
|
||||
} else {
|
||||
console.warn('WARN: rowKey is required when reserve-selection is enabled.');
|
||||
}
|
||||
}
|
||||
|
||||
if (states.fixedColumns.length > 0 || states.rightFixedColumns.length > 0) Vue.nextTick(() => this.table.syncHeight());
|
||||
Vue.nextTick(() => this.table.updateScrollY());
|
||||
@ -65,6 +100,7 @@ TableStore.prototype.mutations = {
|
||||
}
|
||||
if (column.type === 'selection') {
|
||||
states.selectable = column.selectable;
|
||||
states.reserveSelection = column.reserveSelection;
|
||||
}
|
||||
|
||||
this.scheduleLayout();
|
||||
@ -83,38 +119,61 @@ TableStore.prototype.mutations = {
|
||||
states.hoverRow = row;
|
||||
},
|
||||
|
||||
rowSelectedChanged(states) {
|
||||
let isAllSelected = true;
|
||||
const data = states.data || [];
|
||||
for (let i = 0, j = data.length; i < j; i++) {
|
||||
const item = data[i];
|
||||
if (states.selectable) {
|
||||
if (states.selectable.call(null, item, i) && !item.$selected) {
|
||||
isAllSelected = false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (!item.$selected) {
|
||||
isAllSelected = false;
|
||||
break;
|
||||
}
|
||||
rowSelectedChanged(states, row) {
|
||||
const selection = states.selection;
|
||||
if (row.$selected) {
|
||||
if (selection.indexOf(row) === -1) {
|
||||
selection.push(row);
|
||||
}
|
||||
} else {
|
||||
const index = selection.indexOf(row);
|
||||
if (index > -1) {
|
||||
selection.splice(index, 1);
|
||||
}
|
||||
}
|
||||
states.isAllSelected = isAllSelected;
|
||||
this.table.$emit('selection-change', selection);
|
||||
this.table.$emit('select', selection, row);
|
||||
|
||||
this.updateAllSelected();
|
||||
},
|
||||
|
||||
toggleAllSelection: debounce(10, function(states) {
|
||||
const data = states.data || [];
|
||||
const value = !states.isAllSelected;
|
||||
const selection = this.states.selection;
|
||||
let selectionChanged = false;
|
||||
|
||||
const setSelected = (item) => {
|
||||
if (item.$selected !== value) {
|
||||
selectionChanged = true;
|
||||
if (value) {
|
||||
if (selection.indexOf(item) === -1) {
|
||||
selection.push(item);
|
||||
}
|
||||
} else {
|
||||
const itemIndex = selection.indexOf(item);
|
||||
if (itemIndex > -1) {
|
||||
selection.splice(itemIndex, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
item.$selected = value;
|
||||
};
|
||||
|
||||
data.forEach((item, index) => {
|
||||
if (states.selectable) {
|
||||
if (states.selectable.call(null, item, index)) {
|
||||
item.$selected = value;
|
||||
setSelected(item);
|
||||
}
|
||||
} else {
|
||||
item.$selected = value;
|
||||
setSelected(item);
|
||||
}
|
||||
});
|
||||
|
||||
if (selectionChanged) {
|
||||
this.table.$emit('selection-change', selection);
|
||||
}
|
||||
this.table.$emit('select-all', selection);
|
||||
states.isAllSelected = value;
|
||||
}),
|
||||
|
||||
@ -138,25 +197,58 @@ TableStore.prototype.updateColumns = function() {
|
||||
states.columns = [].concat(states.fixedColumns).concat(_columns.filter((column) => !column.fixed)).concat(states.rightFixedColumns);
|
||||
};
|
||||
|
||||
TableStore.prototype.updateSelectedRow = function() {
|
||||
TableStore.prototype.clearSelection = function() {
|
||||
const states = this.states;
|
||||
const oldSelection = states.selection;
|
||||
oldSelection.forEach((row) => { row.$selected = false; });
|
||||
if (this.states.reserveSelection) {
|
||||
const data = states.data || [];
|
||||
data.forEach((row) => { row.$selected = false; });
|
||||
}
|
||||
states.isAllSelected = false;
|
||||
states.selection = [];
|
||||
};
|
||||
|
||||
TableStore.prototype.updateAllSelected = function() {
|
||||
const states = this.states;
|
||||
let isAllSelected = true;
|
||||
const data = states.data || [];
|
||||
for (let i = 0, j = data.length; i < j; i++) {
|
||||
const item = data[i];
|
||||
if (states.selectable) {
|
||||
if (states.selectable.call(null, item, i) && !item.$selected) {
|
||||
isAllSelected = false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (!item.$selected) {
|
||||
isAllSelected = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
states.isAllSelected = isAllSelected;
|
||||
};
|
||||
|
||||
TableStore.prototype.updateCurrentRow = function() {
|
||||
const states = this.states;
|
||||
const table = this.table;
|
||||
const data = states.data || [];
|
||||
if (states.selectionMode === 'single') {
|
||||
const oldSelectedRow = states.currentRow;
|
||||
if (oldSelectedRow === null && !states.allowNoSelection) {
|
||||
const oldCurrentRow = states.currentRow;
|
||||
if (oldCurrentRow === null && !states.allowNoCurrentRow) {
|
||||
states.currentRow = data[0];
|
||||
if (states.currentRow !== oldSelectedRow) {
|
||||
table.$emit('selectionchange', states.currentRow);
|
||||
if (states.currentRow !== oldCurrentRow) {
|
||||
table.$emit('selection-change', states.currentRow);
|
||||
}
|
||||
} else if (data.indexOf(oldSelectedRow) === -1) {
|
||||
if (!states.allowNoSelection) {
|
||||
} else if (data.indexOf(oldCurrentRow) === -1) {
|
||||
if (!states.allowNoCurrentRow) {
|
||||
states.currentRow = data[0];
|
||||
} else {
|
||||
states.currentRow = null;
|
||||
}
|
||||
if (states.currentRow !== oldSelectedRow) {
|
||||
table.$emit('selectionchange', states.currentRow);
|
||||
if (states.currentRow !== oldCurrentRow) {
|
||||
table.$emit('selection-change', states.currentRow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -123,7 +123,9 @@
|
||||
default: 'none'
|
||||
},
|
||||
|
||||
allowNoSelection: Boolean,
|
||||
rowKey: [String, Function],
|
||||
|
||||
allowNoCurrentRow: Boolean,
|
||||
|
||||
rowClassName: [String, Function]
|
||||
},
|
||||
@ -134,6 +136,10 @@
|
||||
},
|
||||
|
||||
methods: {
|
||||
clearSelection() {
|
||||
this.store.clearSelection();
|
||||
},
|
||||
|
||||
handleMouseLeave() {
|
||||
this.store.commit('setHoverRow', null);
|
||||
if (this.hoverState) this.hoverState = null;
|
||||
@ -192,8 +198,7 @@
|
||||
|
||||
selection() {
|
||||
if (this.selectionMode === 'multiple') {
|
||||
const data = this.tableData || [];
|
||||
return data.filter(item => item.$selected === true);
|
||||
return this.store.selection;
|
||||
} else if (this.selectionMode === 'single') {
|
||||
return this.store.currentRow;
|
||||
}
|
||||
@ -218,10 +223,6 @@
|
||||
},
|
||||
|
||||
watch: {
|
||||
selection(val) {
|
||||
this.$emit('selectionchange', val);
|
||||
},
|
||||
|
||||
height(value) {
|
||||
this.layout.setHeight(value);
|
||||
},
|
||||
@ -247,8 +248,9 @@
|
||||
|
||||
data() {
|
||||
const store = new TableStore(this, {
|
||||
allowNoSelection: this.allowNoSelection,
|
||||
selectionMode: this.selectionMode
|
||||
allowNoCurrentRow: this.allowNoCurrentRow,
|
||||
selectionMode: this.selectionMode,
|
||||
rowKey: this.rowKey
|
||||
});
|
||||
const layout = new TableLayout({
|
||||
store,
|
||||
|
Loading…
Reference in New Issue
Block a user