feat: update table

pull/309/head
tangjinzhou 2018-12-11 20:59:23 +08:00
parent f38a45ff2c
commit 4bc2c5ccd2
3 changed files with 138 additions and 60 deletions

View File

@ -1,6 +1,7 @@
import VcTable from '../vc-table' import VcTable from '../vc-table'
import classNames from 'classnames' import classNames from 'classnames'
import shallowEqual from 'shallowequal'
import Pagination from '../pagination' import Pagination from '../pagination'
import Icon from '../icon' import Icon from '../icon'
import Spin from '../spin' import Spin from '../spin'
@ -308,8 +309,8 @@ export default {
} }
}, },
getSorterFn () { getSorterFn (state) {
const { sSortOrder: sortOrder, sSortColumn: sortColumn } = this const { sSortOrder: sortOrder, sSortColumn: sortColumn } = state || this.$data
if (!sortOrder || !sortColumn || if (!sortOrder || !sortColumn ||
typeof sortColumn.sorter !== 'function') { typeof sortColumn.sorter !== 'function') {
return return
@ -323,25 +324,37 @@ export default {
return 0 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) { toggleSortOrder (order, column) {
let { sSortOrder: sortOrder, sSortColumn: sortColumn } = this if (!column.sorter) {
return
}
const { sSortOrder: sortOrder, sSortColumn: sortColumn } = this
// //
const isSortColumn = this.isSortColumn(column) let newSortOrder
if (!isSortColumn) { // // sortOrder
sortOrder = order const oldSortOrder = this.isSameColumn(sortColumn, column) ? sortOrder : undefined
sortColumn = column // //
} else { // if (!oldSortOrder) {
if (sortOrder === order) { // newSortOrder = 'descend'
sortOrder = undefined } else if (oldSortOrder === 'descend') {
sortColumn = null newSortOrder = 'ascend'
} else { // } else {
sortOrder = order newSortOrder = undefined
}
} }
const newState = { const newState = {
sSortOrder: sortOrder, sSortOrder: newSortOrder,
sSortColumn: sortColumn, sSortColumn: newSortOrder ? column : null,
} }
// Controlled // Controlled
@ -423,7 +436,7 @@ export default {
const defaultSelection = this.store.getState().selectionDirty ? [] : this.getDefaultSelection() const defaultSelection = this.store.getState().selectionDirty ? [] : this.getDefaultSelection()
let selectedRowKeys = this.store.getState().selectedRowKeys.concat(defaultSelection) let selectedRowKeys = this.store.getState().selectedRowKeys.concat(defaultSelection)
const key = this.getRecordKey(record, rowIndex) const key = this.getRecordKey(record, rowIndex)
const pivot = this.$data.pivot const { pivot } = this.$data
const rows = this.getFlatCurrentPageData() const rows = this.getFlatCurrentPageData()
let realIndex = rowIndex let realIndex = rowIndex
if (this.$props.expandedRowRender) { if (this.$props.expandedRowRender) {
@ -635,7 +648,7 @@ export default {
}, },
getRecordKey (record, index) { getRecordKey (record, index) {
const rowKey = this.rowKey const { rowKey } = this
const recordKey = (typeof rowKey === 'function') const recordKey = (typeof rowKey === 'function')
? rowKey(record, index) : record[rowKey] ? rowKey(record, index) : record[rowKey]
warning(recordKey !== undefined, warning(recordKey !== undefined,
@ -724,11 +737,11 @@ export default {
renderColumnsDropdown (columns, locale) { renderColumnsDropdown (columns, locale) {
const { prefixCls, dropdownPrefixCls } = this const { prefixCls, dropdownPrefixCls } = this
const { sSortOrder: sortOrder } = this const { sSortOrder: sortOrder } = this
return treeMap(columns, (originColumn, i) => { return treeMap(columns, (column, i) => {
const column = { ...originColumn }
const key = this.getColumnKey(column, i) const key = this.getColumnKey(column, i)
let filterDropdown let filterDropdown
let sortButton let sortButton
const isSortColumn = this.isSortColumn(column)
if ((column.filters && column.filters.length > 0) || column.filterDropdown) { if ((column.filters && column.filters.length > 0) || column.filterDropdown) {
const colFilters = this.sFilters[key] || [] const colFilters = this.sFilters[key] || []
filterDropdown = ( filterDropdown = (
@ -741,53 +754,81 @@ export default {
prefixCls={`${prefixCls}-filter`} prefixCls={`${prefixCls}-filter`}
dropdownPrefixCls={dropdownPrefixCls || 'ant-dropdown'} dropdownPrefixCls={dropdownPrefixCls || 'ant-dropdown'}
getPopupContainer={this.getPopupContainer} getPopupContainer={this.getPopupContainer}
key='filter-dropdown'
/> />
) )
} }
if (column.sorter) { if (column.sorter) {
const isSortColumn = this.isSortColumn(column) // const isSortColumn = this.isSortColumn(column)
if (isSortColumn) { // if (isSortColumn) {
column.className = classNames(column.className, { // column.className = classNames(column.className, {
[`${prefixCls}-column-sort`]: sortOrder, // [`${prefixCls}-column-sort`]: sortOrder,
}) // })
} // }
const isAscend = isSortColumn && sortOrder === 'ascend' const isAscend = isSortColumn && sortOrder === 'ascend'
const isDescend = isSortColumn && sortOrder === 'descend' const isDescend = isSortColumn && sortOrder === 'descend'
sortButton = ( sortButton = (
<div class={`${prefixCls}-column-sorter`}> <div class={`${prefixCls}-column-sorter`} key='sorter'>
<span <Icon
class={`${prefixCls}-column-sorter-up ${isAscend ? 'on' : 'off'}`} class={`${prefixCls}-column-sorter-up ${isAscend ? 'on' : 'off'}`}
title='↑' type='caret-up'
onClick={() => this.toggleSortOrder('ascend', column)} theme='filled'
> />
<Icon type='caret-up' /> <Icon
</span>
<span
class={`${prefixCls}-column-sorter-down ${isDescend ? 'on' : 'off'}`} class={`${prefixCls}-column-sorter-down ${isDescend ? 'on' : 'off'}`}
title='↓' type='caret-down'
onClick={() => this.toggleSortOrder('descend', column)} theme='filled'
> />
<Icon type='caret-down' />
</span>
</div> </div>
) )
} }
column.title = ( return {
<span key={key}> ...column,
{column.title} className: classNames(column.className, {
{sortButton} [`${prefixCls}-column-has-actions`]: sortButton || filterDropdown,
{filterDropdown} [`${prefixCls}-column-has-filters`]: filterDropdown,
</span> [`${prefixCls}-column-has-sorters`]: sortButton,
) [`${prefixCls}-column-sort`]: isSortColumn && sortOrder,
}),
if (sortButton || filterDropdown) { title: [
column.className = classNames(`${prefixCls}-column-has-filters`, column.className) <div
key='title'
title={sortButton ? locale.sortTitle : undefined}
class={sortButton ? `${prefixCls}-column-sorters` : undefined}
onClick={() => this.toggleSortOrder(column)}
>
{this.renderColumnTitle(column.title)}
{sortButton}
</div>,
filterDropdown,
],
} }
// column.title = (
// <span key={key}>
// {column.title}
// {sortButton}
// {filterDropdown}
// </span>
// )
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) { handleShowSizeChange (current, pageSize) {
const pagination = this.sPagination const pagination = this.sPagination
pagination.onShowSizeChange(current, pageSize) pagination.onShowSizeChange(current, pageSize)
@ -854,7 +895,11 @@ export default {
sorter.field = state.sSortColumn.dataIndex sorter.field = state.sSortColumn.dataIndex
sorter.columnKey = this.getColumnKey(state.sSortColumn) sorter.columnKey = this.getColumnKey(state.sSortColumn)
} }
return [pagination, filters, sorter] const extra = {
currentDataSource: this.getLocalData(state),
}
return [pagination, filters, sorter, extra]
}, },
findColumn (myKey) { findColumn (myKey) {
@ -909,12 +954,14 @@ export default {
} : item)) } : item))
}, },
getLocalData () { getLocalData (state) {
const { dataSource, sFilters: filters } = this const currentState = state || this.$data
const { sFilters: filters } = currentState
const { dataSource } = this.$props
let data = dataSource || [] let data = dataSource || []
// //
data = data.slice(0) data = data.slice(0)
const sorterFn = this.getSorterFn() const sorterFn = this.getSorterFn(currentState)
if (sorterFn) { if (sorterFn) {
data = this.recursiveSort(data, sorterFn) data = this.recursiveSort(data, sorterFn)
} }

View File

@ -13,6 +13,13 @@ import { initDefaultProps, getOptionProps } from '../_util/props-util'
import { cloneElement } from '../_util/vnode' import { cloneElement } from '../_util/vnode'
import BaseMixin from '../_util/BaseMixin' import BaseMixin from '../_util/BaseMixin'
function stopPropagation (e) {
e.stopPropagation()
if (e.nativeEvent.stopImmediatePropagation) {
e.nativeEvent.stopImmediatePropagation()
}
}
export default { export default {
mixins: [BaseMixin], mixins: [BaseMixin],
name: 'FilterMenu', name: 'FilterMenu',
@ -76,6 +83,9 @@ export default {
// }, // },
}, },
methods: { methods: {
getDropdownVisible () {
return this.neverShown ? false : this.sVisible
},
setNeverShown (column) { setNeverShown (column) {
const rootNode = this.$el const rootNode = this.$el
const filterBelongToScrollBody = !!closest(rootNode, `.ant-table-scroll`) const filterBelongToScrollBody = !!closest(rootNode, `.ant-table-scroll`)
@ -111,6 +121,12 @@ export default {
handleConfirm () { handleConfirm () {
this.setVisible(false) this.setVisible(false)
this.confirmFilter2() 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) { onVisibleChange (visible) {
@ -188,14 +204,27 @@ export default {
if (typeof filterIcon === 'function') { if (typeof filterIcon === 'function') {
filterIcon = filterIcon(filterd) filterIcon = filterIcon(filterd)
} }
const dropdownSelectedClass = filterd ? `${prefixCls}-selected` : '' const dropdownIconClass = classNames({
[`${prefixCls}-selected`]: filterd,
[`${prefixCls}-open`]: this.getDropdownVisible(),
})
return filterIcon ? cloneElement(filterIcon, { return filterIcon ? cloneElement(filterIcon, {
attrs: { attrs: {
title: locale.filterTitle, title: locale.filterTitle,
}, },
class: classNames(`${prefixCls}-icon`, filterIcon.className), on: {
}) : <Icon title={locale.filterTitle} type='filter' class={dropdownSelectedClass} /> click: stopPropagation,
},
class: classNames(`${prefixCls}-icon`, dropdownIconClass, filterIcon.className),
})
: <Icon
title={locale.filterTitle}
type='filter'
theme='filled'
class={dropdownIconClass}
onClick={stopPropagation}
/>
}, },
}, },
@ -207,7 +236,7 @@ export default {
[`${dropdownPrefixCls}-menu-without-submenu`]: !this.hasSubMenu(), [`${dropdownPrefixCls}-menu-without-submenu`]: !this.hasSubMenu(),
}) })
let { filterDropdown } = column let { filterDropdown } = column
if (filterDropdown && typeof filterDropdown === 'function') { if (filterDropdown instanceof Function) {
filterDropdown = filterDropdown({ filterDropdown = filterDropdown({
prefixCls: `${dropdownPrefixCls}-custom`, prefixCls: `${dropdownPrefixCls}-custom`,
setSelectedKeys: (selectedKeys) => this.setSelectedKeys({ selectedKeys }), setSelectedKeys: (selectedKeys) => this.setSelectedKeys({ selectedKeys }),
@ -257,7 +286,8 @@ export default {
return ( return (
<Dropdown <Dropdown
trigger={['click']} trigger={['click']}
visible={this.neverShown ? false : this.sVisible} placement='bottomRight'
visible={this.getDropdownVisible()}
onVisibleChange={this.onVisibleChange} onVisibleChange={this.onVisibleChange}
getPopupContainer={getPopupContainer} getPopupContainer={getPopupContainer}
forceRender forceRender

View File

@ -63,6 +63,7 @@ export const TableLocale = PropTypes.shape({
emptyText: PropTypes.any, emptyText: PropTypes.any,
selectAll: PropTypes.any, selectAll: PropTypes.any,
selectInvert: PropTypes.any, selectInvert: PropTypes.any,
sortTitle: PropTypes.string,
}).loose }).loose
export const RowSelectionType = PropTypes.oneOf(['checkbox', 'radio']) export const RowSelectionType = PropTypes.oneOf(['checkbox', 'radio'])