Carbon: Table add features and fix bugs (#7682)

* Table: Fix error in calculate `totalFlexWidth`

* Table: Fix error in caculate `scrollX`

* Table: Watch `max-height` change

* Table: Change `toggleRowExpanded`

* Table: Support `obj[key]`

* Table: Update docs for `toggleRowExpanded`

* Table: Add style and class control for every row and cell

* Table: Add `migrating` mixin for `expand`

* Table: Update test spec

* Table: Add `index` in `table-column` for custom index
pull/7720/head
Cyril Su 2017-10-25 02:35:12 -05:00 committed by 杨奕
parent 333a010d3b
commit 25e8503d65
11 changed files with 389 additions and 111 deletions

View File

@ -256,10 +256,10 @@
return row.tag === value; return row.tag === value;
}, },
tableRowClassName(row, index) { tableRowClassName({row, rowIndex}) {
if (index === 1) { if (rowIndex === 1) {
return 'warning-row'; return 'warning-row';
} else if (index === 3) { } else if (rowIndex === 3) {
return 'success-row'; return 'success-row';
} }
return ''; return '';
@ -293,6 +293,10 @@
}; };
} }
} }
},
indexMethod(index) {
return index * 2;
} }
}, },
@ -542,10 +546,10 @@ You can highlight your table content to distinguish between "success, informatio
<script> <script>
export default { export default {
methods: { methods: {
tableRowClassName(row, index) { tableRowClassName({row, rowIndex}) {
if (index === 1) { if (rowIndex === 1) {
return 'warning-row'; return 'warning-row';
} else if (index === 3) { } else if (rowIndex === 3) {
return 'success-row'; return 'success-row';
} }
return ''; return '';
@ -1845,6 +1849,49 @@ Configuring rowspan and colspan allows you to merge cells
``` ```
::: :::
### 自定义索引
自定义 `type=index` 列的行号。
:::demo 通过给 `type=index` 的列传入 `index` 属性,可以自定义索引。该属性传入数字时,将作为索引的起始值。也可以传入一个方法,它提供当前行的行号(从 `0` 开始)作为参数,返回值将作为索引展示。
```html
<template>
<el-table
:data="tableData"
style="width: 100%">
<el-table-column
type="index"
:index="indexMethod">
</el-table-column>
<el-table-column
prop="date"
label="日期"
width="180">
</el-table-column>
<el-table-column
prop="name"
label="姓名"
width="180">
</el-table-column>
<el-table-column
prop="address"
label="地址">
</el-table-column>
</el-table>
</template>
<script>
export default {
methods: {
indexMethod(index) {
return index * 2;
}
}
};
</script>
```
:::
### Table Attributes ### Table Attributes
| Attribute | Description | Type | Accepted Values | Default | | Attribute | Description | Type | Accepted Values | Default |
|---------- |-------------- |---------- |-------------------------------- |-------- | |---------- |-------------- |---------- |-------------------------------- |-------- |
@ -1858,8 +1905,14 @@ Configuring rowspan and colspan allows you to merge cells
| show-header | whether Table header is visible | boolean | — | true | | show-header | whether Table header is visible | boolean | — | true |
| highlight-current-row | whether current row is highlighted | boolean | — | false | | highlight-current-row | whether current row is highlighted | boolean | — | false |
| current-row-key | key of current row, a set only prop | string,number | — | — | | current-row-key | key of current row, a set only prop | string,number | — | — |
| row-class-name | function that returns custom class names for a row, or a string assigning class names for every row | Function(row, index)/String | — | — | | row-class-name | function that returns custom class names for a row, or a string assigning class names for every row | Function({row, rowIndex})/String | — | — |
| row-style | function that returns custom style for a row, or a string assigning custom style for every row | Function(row, index)/Object | — | — | | row-style | function that returns custom style for a row, or a string assigning custom style for every row | Function({row, rowIndex})/Object | — | — |
| cell-class-name | function that returns custom class names for a cell, or a string assigning class names for every cell | Function({row, rowIndex})/String | — | — |
| cell-style | function that returns custom style for a cell, or a string assigning custom style for every cell | Function({row, rowIndex})/Object | — | — |
| header-row-class-name | function that returns custom class names for a row in table header, or a string assigning class names for every row in table header | Function({row, rowIndex})/String | — | — |
| header-row-style | function that returns custom style for a row in table header, or a string assigning custom style for every row in table header | Function({row, rowIndex})/Object | — | — |
| header-cell-class-name | function that returns custom class names for a cell in table header, or a string assigning class names for every cell in table header | Function({row, rowIndex})/String | — | — |
| header-cell-style | function that returns custom style for a cell in table header, or a string assigning custom style for every cell in table header | Function({row, rowIndex})/Object | — | — |
| row-key | key of row data, used for optimizing rendering. Required if `reserve-selection` is on. When its type is String, multi-level access is supported, e.g. `user.info.id`, but `user.info[0].id` is not supported, in which case `Function` should be used. | Function(row)/String | — | — | | row-key | key of row data, used for optimizing rendering. Required if `reserve-selection` is on. When its type is String, multi-level access is supported, e.g. `user.info.id`, but `user.info[0].id` is not supported, in which case `Function` should be used. | Function(row)/String | — | — |
| empty-text | Displayed text when data is empty. You can customize this area with `slot="empty"` | String | — | No Data | | empty-text | Displayed text when data is empty. You can customize this area with `slot="empty"` | String | — | No Data |
| default-expand-all | whether expand all rows by default, only works when the table has a column type="expand" | Boolean | — | false | | default-expand-all | whether expand all rows by default, only works when the table has a column type="expand" | Boolean | — | false |
@ -1889,13 +1942,14 @@ Configuring rowspan and colspan allows you to merge cells
| filter-change | column's key. If you need to use the filter-change event, this attribute is mandatory to identify which column is being filtered | filters | | filter-change | column's key. If you need to use the filter-change event, this attribute is mandatory to identify which column is being filtered | filters |
| current-change | triggers when current row changes | currentRow, oldCurrentRow | | current-change | triggers when current row changes | currentRow, oldCurrentRow |
| header-dragend | triggers when finish dragging header | newWidth, oldWidth, column, event | | header-dragend | triggers when finish dragging header | newWidth, oldWidth, column, event |
| expand | triggers when user expands or collapses a row | row, expanded | | expand-change | triggers when user expands or collapses a row | row, expandedRows |
### Table Methods ### Table Methods
| Method | Description | Parameters | | Method | Description | Parameters |
|------|--------|-------| |------|--------|-------|
| clearSelection | used in multiple selection Table, clear selection, might be useful when `reserve-selection` is on | selection | | clearSelection | used in multiple selection Table, clear selection, might be useful when `reserve-selection` is on | selection |
| toggleRowSelection | used in multiple selection Table, toggle if a certain row is selected. With the second parameter, you can directly set if this row is selected | row, selected | | toggleRowSelection | used in multiple selection Table, toggle if a certain row is selected. With the second parameter, you can directly set if this row is selected | row, selected |
| toggleRowExpanded | used in expand Table, toggle if a certain row is expanded. With the second parameter, you can directly set if this row is expanded | row, expanded |
| setCurrentRow | used in single selection Table, set a certain row selected. If called without any parameter, it will clear selection. | row | | setCurrentRow | used in single selection Table, set a certain row selected. If called without any parameter, it will clear selection. | row |
| clearSort | clear sorting, restore data to the original order | — | | clearSort | clear sorting, restore data to the original order | — |
| clearFilter | clear filter | — | | clearFilter | clear filter | — |
@ -1909,6 +1963,7 @@ Configuring rowspan and colspan allows you to merge cells
| Attribute | Description | Type | Accepted Values | Default | | Attribute | Description | Type | Accepted Values | Default |
|---------- |-------------- |---------- |-------------------------------- |-------- | |---------- |-------------- |---------- |-------------------------------- |-------- |
| type | type of the column. If set to `selection`, the column will display checkbox. If set to `index`, the column will display index of the row (staring from 1). If set to `expand`, the column will display expand icon. | string | selection/index/expand | — | | type | type of the column. If set to `selection`, the column will display checkbox. If set to `index`, the column will display index of the row (staring from 1). If set to `expand`, the column will display expand icon. | string | selection/index/expand | — |
| index | 如果设置了 `type=index`,可以通过传递 `index` 属性来自定义索引 | string, Function(index) | - | - |
| label | column label | string | — | — | | label | column label | string | — | — |
| column-key | column's key. If you need to use the filter-change event, you need this attribute to identify which column is being filtered | string | string | — | — | | column-key | column's key. If you need to use the filter-change event, you need this attribute to identify which column is being filtered | string | string | — | — |
| prop | field name. You can also use its alias: `property` | string | — | — | | prop | field name. You can also use its alias: `property` | string | — | — |

View File

@ -298,10 +298,10 @@
return row.tag === value; return row.tag === value;
}, },
tableRowClassName(row, index) { tableRowClassName({row, rowndex}) {
if (index === 1) { if (rowndex === 1) {
return 'warning-row'; return 'warning-row';
} else if (index === 3) { } else if (rowndex === 3) {
return 'success-row'; return 'success-row';
} }
return ''; return '';
@ -335,6 +335,10 @@
}; };
} }
} }
},
indexMethod(index) {
return index * 2;
} }
}, },
@ -582,10 +586,10 @@
<script> <script>
export default { export default {
methods: { methods: {
tableRowClassName(row, index) { tableRowClassName({row, rowIndex}) {
if (index === 1) { if (rowIndex === 1) {
return 'warning-row'; return 'warning-row';
} else if (index === 3) { } else if (rowIndex === 3) {
return 'success-row'; return 'success-row';
} }
return ''; return '';
@ -1908,6 +1912,49 @@
``` ```
::: :::
### 自定义索引
自定义 `type=index` 列的行号。
:::demo 通过给 `type=index` 的列传入 `index` 属性,可以自定义索引。该属性传入数字时,将作为索引的起始值。也可以传入一个方法,它提供当前行的行号(从 `0` 开始)作为参数,返回值将作为索引展示。
```html
<template>
<el-table
:data="tableData"
style="width: 100%">
<el-table-column
type="index"
:index="indexMethod">
</el-table-column>
<el-table-column
prop="date"
label="日期"
width="180">
</el-table-column>
<el-table-column
prop="name"
label="姓名"
width="180">
</el-table-column>
<el-table-column
prop="address"
label="地址">
</el-table-column>
</el-table>
</template>
<script>
export default {
methods: {
indexMethod(index) {
return index * 2;
}
}
};
</script>
```
:::
### Table Attributes ### Table Attributes
| 参数 | 说明 | 类型 | 可选值 | 默认值 | | 参数 | 说明 | 类型 | 可选值 | 默认值 |
|---------- |-------------- |---------- |-------------------------------- |-------- | |---------- |-------------- |---------- |-------------------------------- |-------- |
@ -1921,8 +1968,14 @@
| show-header | 是否显示表头 | boolean | — | true | | show-header | 是否显示表头 | boolean | — | true |
| highlight-current-row | 是否要高亮当前行 | boolean | — | false | | highlight-current-row | 是否要高亮当前行 | boolean | — | false |
| current-row-key | 当前行的 key只写属性 | String,Number | — | — | | current-row-key | 当前行的 key只写属性 | String,Number | — | — |
| row-class-name | 行的 className 的回调方法,也可以使用字符串为所有行设置一个固定的 className。 | Function(row, index)/String | — | — | | row-class-name | 行的 className 的回调方法,也可以使用字符串为所有行设置一个固定的 className。 | Function({row, rowIndex})/String | — | — |
| row-style | 行的 style 的回调方法,也可以使用一个固定的 Object 为所有行设置一样的 Style。 | Function(row, index)/Object | — | — | | row-style | 行的 style 的回调方法,也可以使用一个固定的 Object 为所有行设置一样的 Style。 | Function({row, rowIndex})/Object | — | — |
| cell-class-name | 单元格的 className 的回调方法,也可以使用字符串为所有单元格设置一个固定的 className。 | Function({row, column, rowIndex, columnIndex})/String | — | — |
| cell-style | 单元格的 style 的回调方法,也可以使用一个固定的 Object 为所有单元格设置一样的 Style。 | Function({row, rowIndex, rowIndex, columnIndex})/Object | — | — |
| header-row-class-name | 表头行的 className 的回调方法,也可以使用字符串为所有表头行设置一个固定的 className。 | Function({row, rowIndex})/String | — | — |
| header-row-style | 表头行的 style 的回调方法,也可以使用一个固定的 Object 为所有表头行设置一样的 Style。 | Function({row, rowIndex})/Object | — | — |
| header-cell-class-name | 表头单元格的 className 的回调方法,也可以使用字符串为所有表头单元格设置一个固定的 className。 | Function({row, column, rowIndex, columnIndex})/String | — | — |
| header-cell-style | 表头单元格的 style 的回调方法,也可以使用一个固定的 Object 为所有表头单元格设置一样的 Style。 | Function({row, rowIndex, rowIndex, columnIndex})/Object | — | — |
| row-key | 行数据的 Key用来优化 Table 的渲染;在使用 reserve-selection 功能的情况下,该属性是必填的。类型为 String 时,支持多层访问:`user.info.id`,但不支持 `user.info[0].id`,此种情况请使用 `Function`。 | Function(row)/String | — | — | | row-key | 行数据的 Key用来优化 Table 的渲染;在使用 reserve-selection 功能的情况下,该属性是必填的。类型为 String 时,支持多层访问:`user.info.id`,但不支持 `user.info[0].id`,此种情况请使用 `Function`。 | Function(row)/String | — | — |
| empty-text | 空数据时显示的文本内容,也可以通过 `slot="empty"` 设置 | String | — | 暂无数据 | | empty-text | 空数据时显示的文本内容,也可以通过 `slot="empty"` 设置 | String | — | 暂无数据 |
| default-expand-all | 是否默认展开所有行,当 Table 中存在 type="expand" 的 Column 的时候有效 | Boolean | — | false | | default-expand-all | 是否默认展开所有行,当 Table 中存在 type="expand" 的 Column 的时候有效 | Boolean | — | false |
@ -1952,13 +2005,14 @@
| filter-change | 当表格的筛选条件发生变化的时候会触发该事件,参数的值是一个对象,对象的 key 是 column 的 columnKey对应的 value 为用户选择的筛选条件的数组。 | filters | | filter-change | 当表格的筛选条件发生变化的时候会触发该事件,参数的值是一个对象,对象的 key 是 column 的 columnKey对应的 value 为用户选择的筛选条件的数组。 | filters |
| current-change | 当表格的当前行发生变化的时候会触发该事件,如果要高亮当前行,请打开表格的 highlight-current-row 属性 | currentRow, oldCurrentRow | | current-change | 当表格的当前行发生变化的时候会触发该事件,如果要高亮当前行,请打开表格的 highlight-current-row 属性 | currentRow, oldCurrentRow |
| header-dragend | 当拖动表头改变了列的宽度的时候会触发该事件 | newWidth, oldWidth, column, event | | header-dragend | 当拖动表头改变了列的宽度的时候会触发该事件 | newWidth, oldWidth, column, event |
| expand | 当用户对某一行展开或者关闭的上会触发该事件 | row, expanded | | expand-change | 当用户对某一行展开或者关闭的时候会触发该事件 | row, expanded |
### Table Methods ### Table Methods
| 方法名 | 说明 | 参数 | | 方法名 | 说明 | 参数 |
| ---- | ---- | ---- | | ---- | ---- | ---- |
| clearSelection | 用于多选表格,清空用户的选择,当使用 reserve-selection 功能的时候,可能会需要使用此方法 | selection | | clearSelection | 用于多选表格,清空用户的选择,当使用 reserve-selection 功能的时候,可能会需要使用此方法 | selection |
| toggleRowSelection | 用于多选表格切换某一行的选中状态如果使用了第二个参数则是设置这一行选中与否selected 为 true 则选中) | row, selected | | toggleRowSelection | 用于多选表格切换某一行的选中状态如果使用了第二个参数则是设置这一行选中与否selected 为 true 则选中) | row, selected |
| toggleRowExpanded | 用于可展开表格切换某一行的展开状态如果使用了第二个参数则是设置这一行展开与否expanded 为 true 则展开) | row, expanded |
| setCurrentRow | 用于单选表格,设定某一行为选中行,如果调用时不加参数,则会取消目前高亮行的选中状态。 | row | | setCurrentRow | 用于单选表格,设定某一行为选中行,如果调用时不加参数,则会取消目前高亮行的选中状态。 | row |
| clearSort | 用于清空排序条件,数据会恢复成未排序的状态 | — | | clearSort | 用于清空排序条件,数据会恢复成未排序的状态 | — |
| clearFilter | 用于清空过滤条件,数据会恢复成未过滤的状态 | — | | clearFilter | 用于清空过滤条件,数据会恢复成未过滤的状态 | — |
@ -1971,7 +2025,8 @@
### Table-column Attributes ### Table-column Attributes
| 参数 | 说明 | 类型 | 可选值 | 默认值 | | 参数 | 说明 | 类型 | 可选值 | 默认值 |
|---------- |-------------- |---------- |-------------------------------- |-------- | |---------- |-------------- |---------- |-------------------------------- |-------- |
| type | 对应列的类型。如果设置了 `selection` 则显示多选框;如果设置了 `index` 则显示该行的索引(从 1 开始计算);如果设置了 expand 则显示为一个可展开的按钮 | string | selection/index/expand | — | | type | 对应列的类型。如果设置了 `selection` 则显示多选框;如果设置了 `index` 则显示该行的索引(从 1 开始计算);如果设置了 `expand` 则显示为一个可展开的按钮 | string | selection/index/expand | — |
| index | 如果设置了 `type=index`,可以通过传递 `index` 属性来自定义索引 | string, Function(index) | - | - |
| column-key | column 的 key如果需要使用 filter-change 事件,则需要此属性标识是哪个 column 的筛选条件 | string | — | — | | column-key | column 的 key如果需要使用 filter-change 事件,则需要此属性标识是哪个 column 的筛选条件 | string | — | — |
| label | 显示的标题 | string | — | — | | label | 显示的标题 | string | — | — |
| prop | 对应列内容的字段名,也可以使用 property 属性 | string | — | — | | prop | 对应列内容的字段名,也可以使用 property 属性 | string | — | — |

View File

@ -32,31 +32,7 @@
<script> <script>
import AsyncValidator from 'async-validator'; import AsyncValidator from 'async-validator';
import emitter from 'element-ui/src/mixins/emitter'; import emitter from 'element-ui/src/mixins/emitter';
import { noop, getPropByPath } from 'element-ui/src/utils/util';
function noop() {}
function getPropByPath(obj, path) {
let tempObj = obj;
path = path.replace(/\[(\w+)\]/g, '.$1');
path = path.replace(/^\./, '');
let keyArr = path.split('.');
let i = 0;
for (let len = keyArr.length; i < len - 1; ++i) {
let key = keyArr[i];
if (key in tempObj) {
tempObj = tempObj[key];
} else {
throw new Error('please transfer a valid prop path to form item!');
}
}
return {
o: tempObj,
k: keyArr[i],
v: tempObj[keyArr[i]]
};
}
export default { export default {
name: 'ElFormItem', name: 'ElFormItem',
@ -148,7 +124,7 @@
path = path.replace(/:/, '.'); path = path.replace(/:/, '.');
} }
return getPropByPath(model, path).v; return getPropByPath(model, path, true).v;
} }
}, },
isRequired() { isRequired() {
@ -226,7 +202,7 @@
path = path.replace(/:/, '.'); path = path.replace(/:/, '.');
} }
let prop = getPropByPath(model, path); let prop = getPropByPath(model, path, true);
if (Array.isArray(value)) { if (Array.isArray(value)) {
this.validateDisabled = true; this.validateDisabled = true;

View File

@ -63,14 +63,8 @@ export default {
if (rowspan === 1 && colspan === 1) { if (rowspan === 1 && colspan === 1) {
return ( return (
<td <td
class={ style={ this.getCellStyle($index, cellIndex, row, column) }
[ class={ this.getCellClass($index, cellIndex, row, column) }
column.id,
column.align,
column.className || '',
columnsHidden[cellIndex] ? 'is-hidden' : ''
]
}
on-mouseenter={ ($event) => this.handleCellMouseEnter($event, row) } on-mouseenter={ ($event) => this.handleCellMouseEnter($event, row) }
on-mouseleave={ this.handleCellMouseLeave }> on-mouseleave={ this.handleCellMouseLeave }>
{ {
@ -92,14 +86,8 @@ export default {
} else { } else {
return ( return (
<td <td
class={ style={ this.getCellStyle($index, cellIndex, row, column) }
[ class={ this.getCellClass($index, cellIndex, row, column) }
column.id,
column.align,
column.className || '',
columnsHidden[cellIndex] ? 'is-hidden' : ''
]
}
rowspan={ rowspan } rowspan={ rowspan }
colspan={ colspan } colspan={ colspan }
on-mouseenter={ ($event) => this.handleCellMouseEnter($event, row) } on-mouseenter={ ($event) => this.handleCellMouseEnter($event, row) }
@ -270,25 +258,31 @@ export default {
}; };
}, },
getRowStyle(row, index) { getRowStyle(row, rowIndex) {
const rowStyle = this.rowStyle; const rowStyle = this.table.rowStyle;
if (typeof rowStyle === 'function') { if (typeof rowStyle === 'function') {
return rowStyle.call(null, row, index); return rowStyle.call(null, {
row,
rowIndex
});
} }
return rowStyle; return rowStyle;
}, },
getRowClass(row, index) { getRowClass(row, rowIndex) {
const classes = ['el-table__row']; const classes = ['el-table__row'];
if (this.stripe && index % 2 === 1) { if (this.stripe && rowIndex % 2 === 1) {
classes.push('el-table__row--striped'); classes.push('el-table__row--striped');
} }
const rowClassName = this.rowClassName; const rowClassName = this.table.rowClassName;
if (typeof rowClassName === 'string') { if (typeof rowClassName === 'string') {
classes.push(rowClassName); classes.push(rowClassName);
} else if (typeof rowClassName === 'function') { } else if (typeof rowClassName === 'function') {
classes.push(rowClassName.call(null, row, index) || ''); classes.push(rowClassName.call(null, {
row,
rowIndex
}));
} }
if (this.store.states.expandRows.indexOf(row) > -1) { if (this.store.states.expandRows.indexOf(row) > -1) {
@ -298,6 +292,41 @@ export default {
return classes.join(' '); return classes.join(' ');
}, },
getCellStyle(rowIndex, columnIndex, row, column) {
const cellStyle = this.table.cellStyle;
if (typeof cellStyle === 'function') {
return cellStyle.call(null, {
rowIndex,
columnIndex,
row,
column
});
}
return cellStyle;
},
getCellClass(rowIndex, columnIndex, row, column) {
const classes = [column.id, column.align, column.className];
if (this.isColumnHidden(columnIndex)) {
classes.push('is-hidden');
}
const cellClassName = this.table.cellClassName;
if (typeof cellClassName === 'string') {
classes.push(cellClassName);
} else if (typeof cellClassName === 'function') {
classes.push(cellClassName.call(null, {
rowIndex,
columnIndex,
row,
column
}));
}
return classes.join(' ');
},
handleCellMouseEnter(event, row) { handleCellMouseEnter(event, row) {
const table = this.table; const table = this.table;
const cell = getCell(event); const cell = getCell(event);
@ -371,7 +400,7 @@ export default {
}, },
handleExpandClick(row) { handleExpandClick(row) {
this.store.commit('toggleRowExpanded', row); this.store.toggleRowExpanded(row);
} }
} }
}; };

View File

@ -1,7 +1,7 @@
import ElCheckbox from 'element-ui/packages/checkbox'; import ElCheckbox from 'element-ui/packages/checkbox';
import ElTag from 'element-ui/packages/tag'; import ElTag from 'element-ui/packages/tag';
import objectAssign from 'element-ui/src/utils/merge'; import objectAssign from 'element-ui/src/utils/merge';
import { getValueByPath } from 'element-ui/src/utils/util'; import { getPropByPath } from 'element-ui/src/utils/util';
let columnIdSeed = 1; let columnIdSeed = 1;
@ -50,8 +50,17 @@ const forced = {
renderHeader: function(h, { column }) { renderHeader: function(h, { column }) {
return column.label || '#'; return column.label || '#';
}, },
renderCell: function(h, { $index }) { renderCell: function(h, { $index, column }) {
return <div>{ $index + 1 }</div>; let i = $index + 1;
const index = column.index;
if (typeof index === 'number') {
i = $index + index;
} else if (typeof index === 'function') {
i = index($index);
}
return <div>{ i }</div>;
}, },
sortable: false sortable: false
}, },
@ -97,9 +106,7 @@ const getDefaultColumn = function(type, options) {
const DEFAULT_RENDER_CELL = function(h, { row, column }) { const DEFAULT_RENDER_CELL = function(h, { row, column }) {
const property = column.property; const property = column.property;
const value = property && property.indexOf('.') === -1 const value = property && getPropByPath(row, property).v;
? row[property]
: getValueByPath(row, property);
if (column && column.formatter) { if (column && column.formatter) {
return column.formatter(row, column, value); return column.formatter(row, column, value);
} }
@ -148,7 +155,8 @@ export default {
filterMultiple: { filterMultiple: {
type: Boolean, type: Boolean,
default: true default: true
} },
index: [Number, Function]
}, },
data() { data() {
@ -238,7 +246,8 @@ export default {
filterMultiple: this.filterMultiple, filterMultiple: this.filterMultiple,
filterOpened: false, filterOpened: false,
filteredValue: this.filteredValue || [], filteredValue: this.filteredValue || [],
filterPlacement: this.filterPlacement || '' filterPlacement: this.filterPlacement || '',
index: this.index
}); });
objectAssign(column, forced[type] || {}); objectAssign(column, forced[type] || {});
@ -354,6 +363,12 @@ export default {
if (this.columnConfig) { if (this.columnConfig) {
this.columnConfig.sortable = newVal; this.columnConfig.sortable = newVal;
} }
},
index(newVal) {
if (this.columnConfig) {
this.columnConfig.index = newVal;
}
} }
}, },

View File

@ -95,7 +95,10 @@ export default {
<thead class={ [{ 'is-group': isGroup, 'has-gutter': this.hasGutter }] }> <thead class={ [{ 'is-group': isGroup, 'has-gutter': this.hasGutter }] }>
{ {
this._l(columnRows, (columns, rowIndex) => this._l(columnRows, (columns, rowIndex) =>
<tr> <tr
style={ this.getHeaderRowStyle(rowIndex) }
class={ this.getHeaderRowClass(rowIndex) }
>
{ {
this._l(columns, (column, cellIndex) => this._l(columns, (column, cellIndex) =>
<th <th
@ -105,7 +108,8 @@ export default {
on-mouseout={ this.handleMouseOut } on-mouseout={ this.handleMouseOut }
on-mousedown={ ($event) => this.handleMouseDown($event, column) } on-mousedown={ ($event) => this.handleMouseDown($event, column) }
on-click={ ($event) => this.handleHeaderClick($event, column) } on-click={ ($event) => this.handleHeaderClick($event, column) }
class={ [column.id, column.order, column.headerAlign, column.className || '', rowIndex === 0 && this.isCellHidden(cellIndex, columns) ? 'is-hidden' : '', !column.children ? 'is-leaf' : '', column.labelClassName, column.sortable ? 'is-sortable' : ''] }> style={ this.getHeaderCellStyle(rowIndex, cellIndex, columns, column) }
class={ this.getHeaderCellClass(rowIndex, cellIndex, columns, column) }>
<div class={ ['cell', column.filteredValue && column.filteredValue.length > 0 ? 'highlight' : '', column.labelClassName] }> <div class={ ['cell', column.filteredValue && column.filteredValue.length > 0 ? 'highlight' : '', column.labelClassName] }>
{ {
column.renderHeader column.renderHeader
@ -172,6 +176,10 @@ export default {
}, },
computed: { computed: {
table() {
return this.$parent;
},
isAllSelected() { isAllSelected() {
return this.store.states.isAllSelected; return this.store.states.isAllSelected;
}, },
@ -256,6 +264,70 @@ export default {
} }
}, },
getHeaderRowStyle(rowIndex) {
const headerRowStyle = this.table.headerRowStyle;
if (typeof headerRowStyle === 'function') {
return headerRowStyle.call(null, { rowIndex });
}
return headerRowStyle;
},
getHeaderRowClass(rowIndex) {
const classes = [];
const headerRowClassName = this.table.headerRowClassName;
if (typeof headerRowClassName === 'string') {
classes.push(headerRowClassName);
} else if (typeof headerRowClassName === 'function') {
classes.push(headerRowClassName.call(null, { rowIndex }));
}
return classes.join(' ');
},
getHeaderCellStyle(rowIndex, columnIndex, row, column) {
const headerCellStyle = this.table.headerCellStyle;
if (typeof headerCellStyle === 'function') {
return headerCellStyle.call(null, {
rowIndex,
columnIndex,
row,
column
});
}
return headerCellStyle;
},
getHeaderCellClass(rowIndex, columnIndex, row, column) {
const classes = [column.id, column.order, column.headerAlign, column.className, column.labelClassName];
if (rowIndex === 0 && this.isCellHidden(columnIndex, row)) {
classes.push('is-hidden');
}
if (!column.children) {
classes.push('is-leaf');
}
if (column.sortable) {
classes.push('is-sortable');
}
const headerCellClassName = this.table.headerCellClassName;
if (typeof headerCellClassName === 'string') {
classes.push(headerCellClassName);
} else if (typeof headerCellClassName === 'function') {
classes.push(headerCellClassName.call(null, {
rowIndex,
columnIndex,
row,
column
}));
}
return classes.join(' ');
},
toggleAllSelection() { toggleAllSelection() {
this.store.commit('toggleAllSelection'); this.store.commit('toggleAllSelection');
}, },

View File

@ -118,10 +118,12 @@ class TableLayout {
bodyMinWidth += column.width || column.minWidth || 80; bodyMinWidth += column.width || column.minWidth || 80;
}); });
if (bodyMinWidth < bodyWidth - this.gutterWidth) { // DON'T HAVE SCROLL BAR const scrollYWidth = this.scrollY ? this.gutterWidth : 0;
if (bodyMinWidth <= bodyWidth - scrollYWidth) { // DON'T HAVE SCROLL BAR
this.scrollX = false; this.scrollX = false;
const totalFlexWidth = bodyWidth - this.gutterWidth - bodyMinWidth; const totalFlexWidth = bodyWidth - scrollYWidth - bodyMinWidth;
if (flexColumns.length === 1) { if (flexColumns.length === 1) {
flexColumns[0].realWidth = (flexColumns[0].minWidth || 80) + totalFlexWidth; flexColumns[0].realWidth = (flexColumns[0].minWidth || 80) + totalFlexWidth;

View File

@ -44,6 +44,36 @@ const toggleRowSelection = function(states, row, selected) {
return changed; return changed;
}; };
const toggleRowExpanded = function(states, row, expanded) {
let changed = false;
const expandRows = states.expandRows;
if (typeof expanded !== 'undefined') {
const index = expandRows.indexOf(row);
if (expanded) {
if (index === -1) {
expandRows.push(row);
changed = true;
}
} else {
if (index !== -1) {
expandRows.splice(index, 1);
changed = true;
}
}
} else {
const index = expandRows.indexOf(row);
if (index === -1) {
expandRows.push(row);
changed = true;
} else {
expandRows.splice(index, 1);
changed = true;
}
}
return changed;
};
const TableStore = function(table, initialState = {}) { const TableStore = function(table, initialState = {}) {
if (!table) { if (!table) {
throw new Error('Table is required.'); throw new Error('Table is required.');
@ -259,26 +289,6 @@ TableStore.prototype.mutations = {
this.updateAllSelected(); this.updateAllSelected();
}, },
toggleRowExpanded: function(states, row, expanded) {
const expandRows = states.expandRows;
if (typeof expanded !== 'undefined') {
const index = expandRows.indexOf(row);
if (expanded) {
if (index === -1) expandRows.push(row);
} else {
if (index !== -1) expandRows.splice(index, 1);
}
} else {
const index = expandRows.indexOf(row);
if (index === -1) {
expandRows.push(row);
} else {
expandRows.splice(index, 1);
}
}
this.table.$emit('expand', row, expandRows.indexOf(row) !== -1);
},
toggleAllSelection: debounce(10, function(states) { toggleAllSelection: debounce(10, function(states) {
const data = states.data || []; const data = states.data || [];
const value = !states.isAllSelected; const value = !states.isAllSelected;
@ -381,6 +391,13 @@ TableStore.prototype.toggleRowSelection = function(row, selected) {
} }
}; };
TableStore.prototype.toggleRowExpanded = function(row, expanded) {
const changed = toggleRowExpanded(this.states, row, expanded);
if (changed) {
this.table.$emit('expand-change', row, this.states.expandRows);
}
};
TableStore.prototype.cleanSelection = function() { TableStore.prototype.cleanSelection = function() {
const selection = this.states.selection || []; const selection = this.states.selection || [];
const data = this.states.data; const data = this.states.data;

View File

@ -156,6 +156,7 @@
import debounce from 'throttle-debounce/debounce'; import debounce from 'throttle-debounce/debounce';
import { addResizeListener, removeResizeListener } from 'element-ui/src/utils/resize-event'; import { addResizeListener, removeResizeListener } from 'element-ui/src/utils/resize-event';
import Locale from 'element-ui/src/mixins/locale'; import Locale from 'element-ui/src/mixins/locale';
import Migrating from 'element-ui/src/mixins/migrating';
import TableStore from './table-store'; import TableStore from './table-store';
import TableLayout from './table-layout'; import TableLayout from './table-layout';
import TableBody from './table-body'; import TableBody from './table-body';
@ -168,7 +169,7 @@
export default { export default {
name: 'ElTable', name: 'ElTable',
mixins: [Locale], mixins: [Locale, Migrating],
props: { props: {
data: { data: {
@ -214,6 +215,18 @@
rowStyle: [Object, Function], rowStyle: [Object, Function],
cellClassName: [String, Function],
cellStyle: [Object, Function],
headerRowClassName: [String, Function],
headerRowStyle: [Object, Function],
headerCellClassName: [String, Function],
headerCellStyle: [Object, Function],
highlightCurrentRow: Boolean, highlightCurrentRow: Boolean,
currentRowKey: [String, Number], currentRowKey: [String, Number],
@ -239,6 +252,14 @@
}, },
methods: { methods: {
getMigratingConfig() {
return {
events: {
expand: 'expand is renamed to `expand-change`'
}
};
},
setCurrentRow(row) { setCurrentRow(row) {
this.store.commit('setCurrentRow', row); this.store.commit('setCurrentRow', row);
}, },
@ -248,6 +269,10 @@
this.store.updateAllSelected(); this.store.updateAllSelected();
}, },
toggleRowExpanded(row, expanded) {
this.store.toggleRowExpanded(row, expanded);
},
clearSelection() { clearSelection() {
this.store.clearSelection(); this.store.clearSelection();
}, },
@ -317,8 +342,8 @@
doLayout() { doLayout() {
this.store.updateColumns(); this.store.updateColumns();
this.layout.update();
this.updateScrollY(); this.updateScrollY();
this.layout.update();
this.$nextTick(() => { this.$nextTick(() => {
if (this.height) { if (this.height) {
this.layout.setHeight(this.height); this.layout.setHeight(this.height);
@ -444,6 +469,10 @@
this.layout.setHeight(value); this.layout.setHeight(value);
}, },
maxHeight(value) {
this.layout.setMaxHeight(value);
},
currentRowKey(newVal) { currentRowKey(newVal) {
this.store.setCurrentRowKey(newVal); this.store.setCurrentRowKey(newVal);
}, },

View File

@ -1,4 +1,7 @@
const hasOwnProperty = Object.prototype.hasOwnProperty; const hasOwnProperty = Object.prototype.hasOwnProperty;
export function noop() {};
export function hasOwn(obj, key) { export function hasOwn(obj, key) {
return hasOwnProperty.call(obj, key); return hasOwnProperty.call(obj, key);
}; };
@ -38,6 +41,31 @@ export const getValueByPath = function(object, prop) {
return result; return result;
}; };
export function getPropByPath(obj, path, strict) {
let tempObj = obj;
path = path.replace(/\[(\w+)\]/g, '.$1');
path = path.replace(/^\./, '');
let keyArr = path.split('.');
let i = 0;
for (let len = keyArr.length; i < len - 1; ++i) {
let key = keyArr[i];
if (key in tempObj) {
tempObj = tempObj[key];
} else {
if (strict) {
throw new Error('please transfer a valid prop path to form item!');
}
break;
}
}
return {
o: tempObj,
k: keyArr[i],
v: tempObj[keyArr[i]]
};
};
export const generateId = function() { export const generateId = function() {
return Math.floor(Math.random() * 10000); return Math.floor(Math.random() * 10000);
}; };

View File

@ -138,10 +138,10 @@ describe('Table', () => {
it('tableRowClassName', done => { it('tableRowClassName', done => {
const vm = createTable(':row-class-name="tableRowClassName"', { const vm = createTable(':row-class-name="tableRowClassName"', {
methods: { methods: {
tableRowClassName(row, index) { tableRowClassName({row, rowIndex}) {
if (index === 1) { if (rowIndex === 1) {
return 'info-row'; return 'info-row';
} else if (index === 3) { } else if (rowIndex === 3) {
return 'positive-row'; return 'positive-row';
} }
@ -171,8 +171,8 @@ describe('Table', () => {
it('tableRowStyle[Function]', done => { it('tableRowStyle[Function]', done => {
const vm = createTable(':row-style="tableRowStyle"', { const vm = createTable(':row-style="tableRowStyle"', {
methods: { methods: {
tableRowStyle(row, index) { tableRowStyle({row, rowIndex}) {
if (index === 1) { if (rowIndex === 1) {
return { height: '60px' }; return { height: '60px' };
} }
@ -897,12 +897,12 @@ describe('Table', () => {
extra = extra || ''; extra = extra || '';
return createVue({ return createVue({
template: ` template: `
<el-table row-key="id" :data="testData" @expand="handleExpand" ${extra}> <el-table row-key="id" :data="testData" @expand-change="handleExpand" ${extra}>
<el-table-column type="expand"> <el-table-column type="expand">
<template slot-scope="props"> <template slot-scope="props">
<div>{{props.row.name}}</div> <div>{{props.row.name}}</div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="release" label="release" /> <el-table-column prop="release" label="release" />
<el-table-column prop="director" label="director" /> <el-table-column prop="director" label="director" />
<el-table-column prop="runtime" label="runtime" /> <el-table-column prop="runtime" label="runtime" />