From 4bc2c5ccd2ddddc8ae9d43c6c0cc9d19b9a15a30 Mon Sep 17 00:00:00 2001 From: tangjinzhou <415800467@qq.com> Date: Tue, 11 Dec 2018 20:59:23 +0800 Subject: [PATCH] feat: update table --- components/table/Table.jsx | 157 ++++++++++++++++++---------- components/table/filterDropdown.jsx | 40 ++++++- components/table/interface.js | 1 + 3 files changed, 138 insertions(+), 60 deletions(-) diff --git a/components/table/Table.jsx b/components/table/Table.jsx index dea5f27f4..6b1c89c1d 100755 --- a/components/table/Table.jsx +++ b/components/table/Table.jsx @@ -1,6 +1,7 @@ import VcTable from '../vc-table' import classNames from 'classnames' +import shallowEqual from 'shallowequal' import Pagination from '../pagination' import Icon from '../icon' import Spin from '../spin' @@ -308,8 +309,8 @@ export default { } }, - getSorterFn () { - const { sSortOrder: sortOrder, sSortColumn: sortColumn } = this + getSorterFn (state) { + const { sSortOrder: sortOrder, sSortColumn: sortColumn } = state || this.$data if (!sortOrder || !sortColumn || typeof sortColumn.sorter !== 'function') { return @@ -323,25 +324,37 @@ export default { return 0 } }, + isSameColumn (a, b) { + if (a && b && a.key && a.key === b.key) { + return true + } + return a === b || shallowEqual(a, b, (value, other) => { + if (typeof value === 'function' && typeof other === 'function') { + return value === other || value.toString() === other.toString() + } + }) + }, toggleSortOrder (order, column) { - let { sSortOrder: sortOrder, sSortColumn: sortColumn } = this + if (!column.sorter) { + return + } + const { sSortOrder: sortOrder, sSortColumn: sortColumn } = this // 只同时允许一列进行排序,否则会导致排序顺序的逻辑问题 - const isSortColumn = this.isSortColumn(column) - if (!isSortColumn) { // 当前列未排序 - sortOrder = order - sortColumn = column - } else { // 当前列已排序 - if (sortOrder === order) { // 切换为未排序状态 - sortOrder = undefined - sortColumn = null - } else { // 切换为排序状态 - sortOrder = order - } + let newSortOrder + // 切换另一列时,丢弃 sortOrder 的状态 + const oldSortOrder = this.isSameColumn(sortColumn, column) ? sortOrder : undefined + // 切换排序状态,按照降序/升序/不排序的顺序 + if (!oldSortOrder) { + newSortOrder = 'descend' + } else if (oldSortOrder === 'descend') { + newSortOrder = 'ascend' + } else { + newSortOrder = undefined } const newState = { - sSortOrder: sortOrder, - sSortColumn: sortColumn, + sSortOrder: newSortOrder, + sSortColumn: newSortOrder ? column : null, } // Controlled @@ -423,7 +436,7 @@ export default { const defaultSelection = this.store.getState().selectionDirty ? [] : this.getDefaultSelection() let selectedRowKeys = this.store.getState().selectedRowKeys.concat(defaultSelection) const key = this.getRecordKey(record, rowIndex) - const pivot = this.$data.pivot + const { pivot } = this.$data const rows = this.getFlatCurrentPageData() let realIndex = rowIndex if (this.$props.expandedRowRender) { @@ -635,7 +648,7 @@ export default { }, getRecordKey (record, index) { - const rowKey = this.rowKey + const { rowKey } = this const recordKey = (typeof rowKey === 'function') ? rowKey(record, index) : record[rowKey] warning(recordKey !== undefined, @@ -724,11 +737,11 @@ export default { renderColumnsDropdown (columns, locale) { const { prefixCls, dropdownPrefixCls } = this const { sSortOrder: sortOrder } = this - return treeMap(columns, (originColumn, i) => { - const column = { ...originColumn } + return treeMap(columns, (column, i) => { const key = this.getColumnKey(column, i) let filterDropdown let sortButton + const isSortColumn = this.isSortColumn(column) if ((column.filters && column.filters.length > 0) || column.filterDropdown) { const colFilters = this.sFilters[key] || [] filterDropdown = ( @@ -741,53 +754,81 @@ export default { prefixCls={`${prefixCls}-filter`} dropdownPrefixCls={dropdownPrefixCls || 'ant-dropdown'} getPopupContainer={this.getPopupContainer} + key='filter-dropdown' /> ) } if (column.sorter) { - const isSortColumn = this.isSortColumn(column) - if (isSortColumn) { - column.className = classNames(column.className, { - [`${prefixCls}-column-sort`]: sortOrder, - }) - } + // const isSortColumn = this.isSortColumn(column) + // if (isSortColumn) { + // column.className = classNames(column.className, { + // [`${prefixCls}-column-sort`]: sortOrder, + // }) + // } const isAscend = isSortColumn && sortOrder === 'ascend' const isDescend = isSortColumn && sortOrder === 'descend' sortButton = ( -
- + this.toggleSortOrder('ascend', column)} - > - - - + this.toggleSortOrder('descend', column)} - > - - + type='caret-down' + theme='filled' + />
) } - column.title = ( - - {column.title} - {sortButton} - {filterDropdown} - - ) - - if (sortButton || filterDropdown) { - column.className = classNames(`${prefixCls}-column-has-filters`, column.className) + return { + ...column, + className: classNames(column.className, { + [`${prefixCls}-column-has-actions`]: sortButton || filterDropdown, + [`${prefixCls}-column-has-filters`]: filterDropdown, + [`${prefixCls}-column-has-sorters`]: sortButton, + [`${prefixCls}-column-sort`]: isSortColumn && sortOrder, + }), + title: [ +
this.toggleSortOrder(column)} + > + {this.renderColumnTitle(column.title)} + {sortButton} +
, + filterDropdown, + ], } + // column.title = ( + // + // {column.title} + // {sortButton} + // {filterDropdown} + // + // ) - return column + // if (sortButton || filterDropdown) { + // column.className = classNames(`${prefixCls}-column-has-filters`, column.className) + // } + + // return column }) }, - + renderColumnTitle (title) { + const { sFilters: filters, sSortOrder: sortOrder } = this.$data + // https://github.com/ant-design/ant-design/issues/11246#issuecomment-405009167 + if (title instanceof Function) { + return title({ + filters, + sortOrder, + }) + } + return title + }, handleShowSizeChange (current, pageSize) { const pagination = this.sPagination pagination.onShowSizeChange(current, pageSize) @@ -854,7 +895,11 @@ export default { sorter.field = state.sSortColumn.dataIndex sorter.columnKey = this.getColumnKey(state.sSortColumn) } - return [pagination, filters, sorter] + const extra = { + currentDataSource: this.getLocalData(state), + } + + return [pagination, filters, sorter, extra] }, findColumn (myKey) { @@ -909,12 +954,14 @@ export default { } : item)) }, - getLocalData () { - const { dataSource, sFilters: filters } = this + getLocalData (state) { + const currentState = state || this.$data + const { sFilters: filters } = currentState + const { dataSource } = this.$props let data = dataSource || [] // 优化本地排序 data = data.slice(0) - const sorterFn = this.getSorterFn() + const sorterFn = this.getSorterFn(currentState) if (sorterFn) { data = this.recursiveSort(data, sorterFn) } diff --git a/components/table/filterDropdown.jsx b/components/table/filterDropdown.jsx index 567660c1d..d7c6bb3aa 100755 --- a/components/table/filterDropdown.jsx +++ b/components/table/filterDropdown.jsx @@ -13,6 +13,13 @@ import { initDefaultProps, getOptionProps } from '../_util/props-util' import { cloneElement } from '../_util/vnode' import BaseMixin from '../_util/BaseMixin' +function stopPropagation (e) { + e.stopPropagation() + if (e.nativeEvent.stopImmediatePropagation) { + e.nativeEvent.stopImmediatePropagation() + } +} + export default { mixins: [BaseMixin], name: 'FilterMenu', @@ -76,6 +83,9 @@ export default { // }, }, methods: { + getDropdownVisible () { + return this.neverShown ? false : this.sVisible + }, setNeverShown (column) { const rootNode = this.$el const filterBelongToScrollBody = !!closest(rootNode, `.ant-table-scroll`) @@ -111,6 +121,12 @@ export default { handleConfirm () { this.setVisible(false) this.confirmFilter2() + // Call `setSelectedKeys` & `confirm` in the same time will make filter data not up to date + // https://github.com/ant-design/ant-design/issues/12284 + this.$forceUpdate() + this.$nextTick(() => { + this.confirmFilter + }) }, onVisibleChange (visible) { @@ -188,14 +204,27 @@ export default { if (typeof filterIcon === 'function') { filterIcon = filterIcon(filterd) } - const dropdownSelectedClass = filterd ? `${prefixCls}-selected` : '' + const dropdownIconClass = classNames({ + [`${prefixCls}-selected`]: filterd, + [`${prefixCls}-open`]: this.getDropdownVisible(), + }) return filterIcon ? cloneElement(filterIcon, { attrs: { title: locale.filterTitle, }, - class: classNames(`${prefixCls}-icon`, filterIcon.className), - }) : + on: { + click: stopPropagation, + }, + class: classNames(`${prefixCls}-icon`, dropdownIconClass, filterIcon.className), + }) + : }, }, @@ -207,7 +236,7 @@ export default { [`${dropdownPrefixCls}-menu-without-submenu`]: !this.hasSubMenu(), }) let { filterDropdown } = column - if (filterDropdown && typeof filterDropdown === 'function') { + if (filterDropdown instanceof Function) { filterDropdown = filterDropdown({ prefixCls: `${dropdownPrefixCls}-custom`, setSelectedKeys: (selectedKeys) => this.setSelectedKeys({ selectedKeys }), @@ -257,7 +286,8 @@ export default { return (