Skip to content

Commit

Permalink
Update Table:
Browse files Browse the repository at this point in the history
1. Add rowKey prop for Table.
2. Add clearSelection method for Table.
2. Add reserveSelection prop for TableColumn[type="selection"]
  • Loading branch information
furybean authored and QingWei-Li committed Oct 19, 2016
1 parent e396db7 commit 6ab0d57
Show file tree
Hide file tree
Showing 6 changed files with 167 additions and 61 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
34 changes: 22 additions & 12 deletions examples/docs/zh-cn/table.md
Original file line number Diff line number Diff line change
Expand Up @@ -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">
Expand Down Expand Up @@ -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">
Expand Down Expand Up @@ -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
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
Expand All @@ -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 |
14 changes: 6 additions & 8 deletions packages/table/src/table-body.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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) {
Expand All @@ -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) {
Expand Down
6 changes: 4 additions & 2 deletions packages/table/src/table-column.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -117,7 +117,8 @@ export default {
},
fixed: [Boolean, String],
formatter: Function,
selectable: Function
selectable: Function,
reserveSelection: Boolean
},

render() {},
Expand Down Expand Up @@ -203,6 +204,7 @@ export default {
showTooltipWhenOverflow: this.showTooltipWhenOverflow,
formatter: this.formatter,
selectable: this.selectable,
reserveSelection: this.reserveSelection,
fixed: this.fixed
});

Expand Down
152 changes: 122 additions & 30 deletions packages/table/src/table-store.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,23 @@ 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.');
}
this.table = table;

this.states = {
rowKey: null,
_columns: [],
columns: [],
fixedColumns: [],
Expand All @@ -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,
Expand All @@ -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());
Expand All @@ -65,6 +100,7 @@ TableStore.prototype.mutations = {
}
if (column.type === 'selection') {
states.selectable = column.selectable;
states.reserveSelection = column.reserveSelection;
}

this.scheduleLayout();
Expand All @@ -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;
}),

Expand All @@ -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);
}
}
}
Expand Down

0 comments on commit 6ab0d57

Please sign in to comment.