diff --git a/components/table/Table.jsx b/components/table/Table.jsx
index d53f5dffc..3219dc6f8 100755
--- a/components/table/Table.jsx
+++ b/components/table/Table.jsx
@@ -1,5 +1,4 @@
-import cloneDeep from 'lodash/cloneDeep'
import VcTable from '../vc-table'
import classNames from 'classnames'
import Pagination from '../pagination'
@@ -33,10 +32,8 @@ function stopPropagation (e) {
}
const defaultPagination = {
- on: {
- change: noop,
- showSizeChange: noop,
- },
+ onChange: noop,
+ onShowSizeChange: noop,
}
/**
@@ -91,14 +88,13 @@ export default {
watch: {
pagination (val) {
this.setState(previousState => {
- const newPagination = mergeProps(
- defaultPagination,
- previousState.sPagination,
- val,
- )
- newPagination.props = newPagination.props || {}
- newPagination.props.current = newPagination.props.current || 1
- newPagination.props.pageSize = newPagination.props.pageSize || 10
+ const newPagination = {
+ ...defaultPagination,
+ ...previousState.sPagination,
+ ...val,
+ }
+ newPagination.current = newPagination.current || 1
+ newPagination.pageSize = newPagination.pageSize || 10
return { sPagination: val !== false ? newPagination : emptyObject }
})
},
@@ -176,17 +172,13 @@ export default {
getDefaultPagination (props) {
const pagination = props.pagination || {}
- pagination.props = pagination.props || {}
return this.hasPagination(props)
- ? mergeProps(
- defaultPagination,
- pagination,
- {
- props: {
- current: pagination.props.defaultCurrent || pagination.props.current || 1,
- pageSize: pagination.props.defaultPageSize || pagination.props.pageSize || 10,
- },
- }) : {}
+ ? {
+ ...defaultPagination,
+ ...pagination,
+ current: pagination.defaultCurrent || pagination.current || 1,
+ pageSize: pagination.defaultPageSize || pagination.pageSize || 10,
+ } : {}
},
onRow (record, index) {
@@ -345,7 +337,7 @@ export default {
if (this.getSortOrderColumns().length === 0) {
this.setState(newState)
}
- this.$emit('change', this.prepareParamsArguments({
+ this.$emit('change', ...this.prepareParamsArguments({
...this.$data,
...newState,
}))
@@ -373,9 +365,8 @@ export default {
if (props.pagination) {
// Reset current prop
- pagination.props = pagination.props || {}
- pagination.props.current = 1
- pagination.on.change(pagination.current)
+ pagination.current = 1
+ pagination.onChange(pagination.current)
}
const newState = {
@@ -395,23 +386,22 @@ export default {
}
// Controlled current prop will not respond user interaction
- if (typeof props.pagination === 'object' && props.pagination.props && 'current' in (props.pagination.props)) {
- newState.sPagination = mergeProps(pagination, {
- props: {
- current: this.sPagination.props.current,
- },
- })
+ if (typeof props.pagination === 'object' && 'current' in (props.pagination)) {
+ newState.sPagination = {
+ ...pagination,
+ current: this.sPagination.current,
+ }
}
this.setState(newState, () => {
this.store.setState({
selectionDirty: false,
})
- this.$emit('change', this.prepareParamsArguments({
+ this.$emit('change', ...this.prepareParamsArguments({
...this.$data,
- selectionDirty: false,
- filters,
- pagination,
+ sSelectionDirty: false,
+ sFilters: filters,
+ sPagination: pagination,
}))
})
},
@@ -523,11 +513,11 @@ export default {
const props = this.$props
const pagination = { ...this.sPagination }
if (current) {
- pagination.props.current = current
+ pagination.current = current
} else {
- pagination.props.current = pagination.props.current || 1
+ pagination.current = pagination.current || 1
}
- pagination.on.change(pagination.props.current, ...otherArguments)
+ pagination.onChange(pagination.current, ...otherArguments)
const newState = {
sPagination: pagination,
@@ -535,23 +525,21 @@ export default {
// Controlled current prop will not respond user interaction
if (props.pagination &&
typeof props.pagination === 'object' &&
- props.pagination.props &&
- 'current' in (props.pagination.props)) {
- newState.sPagination = mergeProps(pagination, {
- props: {
- current: this.sPagination.props.current,
- },
- })
+ 'current' in (props.pagination)) {
+ newState.sPagination = {
+ ...pagination,
+ current: this.sPagination.current,
+ }
}
this.setState(newState)
this.store.setState({
selectionDirty: false,
})
- this.$emit('change', this.prepareParamsArguments({
+ this.$emit('change', ...this.prepareParamsArguments({
...this.$data,
- selectionDirty: false,
- pagination,
+ sSelectionDirty: false,
+ sPagination: pagination,
}))
},
@@ -655,7 +643,7 @@ export default {
},
getMaxCurrent (total) {
- const { current, pageSize } = this.sPagination.props
+ const { current, pageSize } = this.sPagination
if ((current - 1) * pageSize >= total) {
return Math.floor((total - 1) / pageSize) + 1
}
@@ -738,17 +726,16 @@ export default {
handleShowSizeChange (current, pageSize) {
const pagination = this.sPagination
- pagination.on.showSizeChange(current, pageSize)
- const nextPagination = mergeProps(pagination, {
- props: {
- pageSize,
- current,
- },
- })
+ pagination.onShowSizeChange(current, pageSize)
+ const nextPagination = {
+ ...pagination,
+ pageSize,
+ current,
+ }
this.setState({ sPagination: nextPagination })
- this.$emit('change', this.prepareParamsArguments({
+ this.$emit('change', ...this.prepareParamsArguments({
...this.$data,
- pagination: nextPagination,
+ sPagination: nextPagination,
}))
},
@@ -759,25 +746,24 @@ export default {
}
let size = 'default'
const { sPagination: pagination } = this
- if (pagination.props && pagination.props.size) {
- size = pagination.props.size
+ if (pagination.size) {
+ size = pagination.size
} else if (this.size === 'middle' || this.size === 'small') {
size = 'small'
}
- const total = (pagination.props && pagination.props.total) || this.getLocalData().length
- const { class: cls, style, on, props } = pagination
+ const total = pagination.total || this.getLocalData().length
+ const { class: cls, style, onChange, onShowSizeChange, ...restProps } = pagination // eslint-disable-line
const paginationProps = mergeProps({
key: 'pagination',
class: classNames(cls, `${this.prefixCls}-pagination`),
props: {
- ...props,
+ ...restProps,
total,
size,
current: this.getMaxCurrent(total),
},
style,
on: {
- ...on,
change: this.handlePageChange,
showSizeChange: this.handleShowSizeChange,
},
@@ -791,12 +777,10 @@ export default {
// Get pagination, filters, sorter
prepareParamsArguments (state) {
- const pagination = cloneDeep(state.sPagination)
+ const pagination = { ...state.sPagination }
// remove useless handle function in Table.onChange
- if (pagination.on) {
- delete pagination.on.change
- delete pagination.on.showSizeChange
- }
+ delete pagination.onChange
+ delete pagination.onShowSizeChange
const filters = state.sFilters
const sorter = {}
if (state.sSortColumn && state.sSortOrder) {
@@ -822,14 +806,14 @@ export default {
let data = this.getLocalData()
let current
let pageSize
- const pagProps = this.sPagination.props || {}
+ const sPagination = this.sPagination
// 如果没有分页的话,默认全部展示
if (!this.hasPagination()) {
pageSize = Number.MAX_VALUE
current = 1
} else {
- pageSize = pagProps.pageSize
- current = this.getMaxCurrent(pagProps.total || data.length)
+ pageSize = sPagination.pageSize
+ current = this.getMaxCurrent(sPagination.total || data.length)
}
// 分页
diff --git a/components/table/demo/ajax.md b/components/table/demo/ajax.md
new file mode 100644
index 000000000..a79a065a9
--- /dev/null
+++ b/components/table/demo/ajax.md
@@ -0,0 +1,99 @@
+
+#### 远程加载数据
+这个例子通过简单的 ajax 读取方式,演示了如何从服务端读取并展现数据,具有筛选、排序等功能以及页面 loading 效果。开发者可以自行接入其他数据处理方式。
+另外,本例也展示了筛选排序功能如何交给服务端实现,列不需要指定具体的 `onFilter` 和 `sorter` 函数,而是在把筛选和排序的参数发到服务端来处理。
+**注意,此示例使用 [模拟接口](https://randomuser.me),展示数据可能不准确,请打开网络面板查看请求。**
+
+
+
+#### Ajax
+This example shows how to fetch and present data from remote server, and how to implement filtering and sorting in server side by sending related parameters to server.
+**Note, this example use [Mock API](https://randomuser.me) that you can look up in Network Console.**
+
+
+```html
+
+
+
+ {{name.first}} {{name.last}}
+
+
+
+
+```
diff --git a/components/table/demo/basic.4.md b/components/table/demo/basic.4.md
new file mode 100644
index 000000000..332ec9843
--- /dev/null
+++ b/components/table/demo/basic.4.md
@@ -0,0 +1,76 @@
+
+#### 基本用法
+简单的表格,最后一列是各种操作。
+
+
+
+#### basic Usage
+Simple table with actions.
+
+
+```html
+
+
+
+ {{text}}
+
+
+
+ Action 一 {{record.name}}
+
+ Delete
+
+
+ More actions
+
+
+
+
+
+
+```
diff --git a/components/table/demo/basic.5.md b/components/table/demo/basic.5.md
new file mode 100644
index 000000000..332ec9843
--- /dev/null
+++ b/components/table/demo/basic.5.md
@@ -0,0 +1,76 @@
+
+#### 基本用法
+简单的表格,最后一列是各种操作。
+
+
+
+#### basic Usage
+Simple table with actions.
+
+
+```html
+
+
+
+ {{text}}
+
+
+
+ Action 一 {{record.name}}
+
+ Delete
+
+
+ More actions
+
+
+
+
+
+
+```
diff --git a/components/table/demo/basic.6.md b/components/table/demo/basic.6.md
new file mode 100644
index 000000000..332ec9843
--- /dev/null
+++ b/components/table/demo/basic.6.md
@@ -0,0 +1,76 @@
+
+#### 基本用法
+简单的表格,最后一列是各种操作。
+
+
+
+#### basic Usage
+Simple table with actions.
+
+
+```html
+
+
+
+ {{text}}
+
+
+
+ Action 一 {{record.name}}
+
+ Delete
+
+
+ More actions
+
+
+
+
+
+
+```
diff --git a/components/table/demo/basic.7.md b/components/table/demo/basic.7.md
new file mode 100644
index 000000000..332ec9843
--- /dev/null
+++ b/components/table/demo/basic.7.md
@@ -0,0 +1,76 @@
+
+#### 基本用法
+简单的表格,最后一列是各种操作。
+
+
+
+#### basic Usage
+Simple table with actions.
+
+
+```html
+
+
+
+ {{text}}
+
+
+
+ Action 一 {{record.name}}
+
+ Delete
+
+
+ More actions
+
+
+
+
+
+
+```
diff --git a/components/table/demo/basic.8.md b/components/table/demo/basic.8.md
new file mode 100644
index 000000000..332ec9843
--- /dev/null
+++ b/components/table/demo/basic.8.md
@@ -0,0 +1,76 @@
+
+#### 基本用法
+简单的表格,最后一列是各种操作。
+
+
+
+#### basic Usage
+Simple table with actions.
+
+
+```html
+
+
+
+ {{text}}
+
+
+
+ Action 一 {{record.name}}
+
+ Delete
+
+
+ More actions
+
+
+
+
+
+
+```
diff --git a/components/table/demo/basic.9.md b/components/table/demo/basic.9.md
new file mode 100644
index 000000000..332ec9843
--- /dev/null
+++ b/components/table/demo/basic.9.md
@@ -0,0 +1,76 @@
+
+#### 基本用法
+简单的表格,最后一列是各种操作。
+
+
+
+#### basic Usage
+Simple table with actions.
+
+
+```html
+
+
+
+ {{text}}
+
+
+
+ Action 一 {{record.name}}
+
+ Delete
+
+
+ More actions
+
+
+
+
+
+
+```
diff --git a/components/table/demo/bordered.md b/components/table/demo/bordered.md
new file mode 100644
index 000000000..9de3f49c3
--- /dev/null
+++ b/components/table/demo/bordered.md
@@ -0,0 +1,71 @@
+
+#### 带边框
+添加表格边框线,页头和页脚。
+
+
+
+#### border, title and footer
+Add border, title and footer for table.
+
+
+```html
+
+
+
+ {{text}}
+
+
+ Header
+
+
+ Footer
+
+
+
+
+
+```
diff --git a/components/table/demo/colspan-rowspan.md b/components/table/demo/colspan-rowspan.md
new file mode 100644
index 000000000..46289664e
--- /dev/null
+++ b/components/table/demo/colspan-rowspan.md
@@ -0,0 +1,143 @@
+
+#### 表格行/列合并
+表头只支持列合并,使用 column 里的 colSpan 进行设置。
+表格支持行/列合并,使用 render 里的单元格属性 colSpan 或者 rowSpan 设值为 0 时,设置的表格不会渲染。
+
+
+
+#### colSpan and rowSpan
+Table column title supports `colSpan` that set in `column`.
+Table cell supports `colSpan` and `rowSpan` that set in render return object. When each of them is set to `0`, the cell will not be rendered.
+
+
+```html
+
+
+
+ {{text}}
+
+
+
+ Action 一 {{record.name}}
+
+ Delete
+
+
+ More actions
+
+
+
+
+
+
+```
diff --git a/components/table/filterDropdown.jsx b/components/table/filterDropdown.jsx
index 3844f62ad..203ea0515 100755
--- a/components/table/filterDropdown.jsx
+++ b/components/table/filterDropdown.jsx
@@ -37,142 +37,139 @@ export default {
this.setNeverShown(column)
})
},
-
- componentWillReceiveProps (nextProps) {
- const { column } = nextProps
- this.setNeverShown(column)
- const newState = {}
- if ('selectedKeys' in nextProps) {
- newState.selectedKeys = nextProps.selectedKeys
- }
- if ('filterDropdownVisible' in column) {
- newState.visible = column.filterDropdownVisible
- }
- if (Object.keys(newState).length > 0) {
- this.setState(newState)
- }
+ watch: {
+ 'column.fixed': function (val) {
+ this.setNeverShown(this.column)
+ },
+ column (val) {
+ if ('filterDropdownVisible' in val) {
+ this.sVisible = val.filterDropdownVisible
+ }
+ },
+ selectedKeys (val) {
+ this.sSelectedKeys = val
+ },
},
methods: {
-
- },
-
- setNeverShown (column) {
- const rootNode = this.$el
- const filterBelongToScrollBody = !!closest(rootNode, `.ant-table-scroll`)
- if (filterBelongToScrollBody) {
- // When fixed column have filters, there will be two dropdown menus
- // Filter dropdown menu inside scroll body should never be shown
- // To fix https://github.com/ant-design/ant-design/issues/5010 and
- // https://github.com/ant-design/ant-design/issues/7909
- this.neverShown = !!column.fixed
- }
- },
-
- setSelectedKeys ({ selectedKeys }) {
- this.setState({ sSelectedKeys: selectedKeys })
- },
-
- setVisible (visible) {
- const { column } = this
- if (!('filterDropdownVisible' in column)) {
- this.setState({ sVisible: visible })
- }
- if (column.onFilterDropdownVisibleChange) {
- column.onFilterDropdownVisibleChange(visible)
- }
- },
-
- handleClearFilters () {
- this.setState({
- sSelectedKeys: [],
- }, this.handleConfirm)
- },
-
- handleConfirm () {
- this.setVisible(false)
- this.confirmFilter()
- },
-
- onVisibleChange (visible) {
- this.setVisible(visible)
- if (!visible) {
- this.confirmFilter()
- }
- },
-
- confirmFilter () {
- if (this.sSelectedKeys !== this.selectedKeys) {
- this.confirmFilter(this.column, this.sSelectedKeys)
- }
- },
-
- renderMenuItem (item) {
- const { column } = this
- const multiple = ('filterMultiple' in column) ? column.filterMultiple : true
- const input = multiple ? (
- = 0} />
- ) : (
- = 0} />
- )
-
- return (
-
- )
- },
-
- hasSubMenu () {
- const { column: { filters = [] }} = this
- return filters.some(item => !!(item.children && item.children.length > 0))
- },
-
- renderMenus (items) {
- return items.map(item => {
- if (item.children && item.children.length > 0) {
- const { sKeyPathOfSelectedItem } = this
- const containSelected = Object.keys(sKeyPathOfSelectedItem).some(
- key => sKeyPathOfSelectedItem[key].indexOf(item.value) >= 0,
- )
- const subMenuCls = containSelected ? `${this.dropdownPrefixCls}-submenu-contain-selected` : ''
- return (
-
- )
+ setNeverShown (column) {
+ const rootNode = this.$el
+ const filterBelongToScrollBody = !!closest(rootNode, `.ant-table-scroll`)
+ if (filterBelongToScrollBody) {
+ // When fixed column have filters, there will be two dropdown menus
+ // Filter dropdown menu inside scroll body should never be shown
+ // To fix https://github.com/ant-design/ant-design/issues/5010 and
+ // https://github.com/ant-design/ant-design/issues/7909
+ this.neverShown = !!column.fixed
}
- return this.renderMenuItem(item)
- })
+ },
+
+ setSelectedKeys ({ selectedKeys }) {
+ this.setState({ sSelectedKeys: selectedKeys })
+ },
+
+ setVisible (visible) {
+ const { column } = this
+ if (!('filterDropdownVisible' in column)) {
+ this.setState({ sVisible: visible })
+ }
+ if (column.onFilterDropdownVisibleChange) {
+ column.onFilterDropdownVisibleChange(visible)
+ }
+ },
+
+ handleClearFilters () {
+ this.setState({
+ sSelectedKeys: [],
+ }, this.handleConfirm)
+ },
+
+ handleConfirm () {
+ this.setVisible(false)
+ this.confirmFilter2()
+ },
+
+ onVisibleChange (visible) {
+ this.setVisible(visible)
+ if (!visible) {
+ this.confirmFilter2()
+ }
+ },
+
+ confirmFilter2 () {
+ if (this.sSelectedKeys !== this.selectedKeys) {
+ this.confirmFilter(this.column, this.sSelectedKeys)
+ }
+ },
+
+ renderMenuItem (item) {
+ const { column } = this
+ const multiple = ('filterMultiple' in column) ? column.filterMultiple : true
+ const input = multiple ? (
+ = 0} />
+ ) : (
+ = 0} />
+ )
+
+ return (
+
+ )
+ },
+
+ hasSubMenu () {
+ const { column: { filters = [] }} = this
+ return filters.some(item => !!(item.children && item.children.length > 0))
+ },
+
+ renderMenus (items) {
+ return items.map(item => {
+ if (item.children && item.children.length > 0) {
+ const { sKeyPathOfSelectedItem } = this
+ const containSelected = Object.keys(sKeyPathOfSelectedItem).some(
+ key => sKeyPathOfSelectedItem[key].indexOf(item.value) >= 0,
+ )
+ const subMenuCls = containSelected ? `${this.dropdownPrefixCls}-submenu-contain-selected` : ''
+ return (
+
+ )
+ }
+ return this.renderMenuItem(item)
+ })
+ },
+
+ handleMenuItemClick (info) {
+ if (info.keyPath.length <= 1) {
+ return
+ }
+ const keyPathOfSelectedItem = this.sKeyPathOfSelectedItem
+ if (this.sSelectedKeys.indexOf(info.key) >= 0) {
+ // deselect SubMenu child
+ delete keyPathOfSelectedItem[info.key]
+ } else {
+ // select SubMenu child
+ keyPathOfSelectedItem[info.key] = info.keyPath
+ }
+ this.setState({ keyPathOfSelectedItem })
+ },
+
+ renderFilterIcon () {
+ const { column, locale, prefixCls } = this
+ const filterIcon = column.filterIcon
+ const dropdownSelectedClass = this.selectedKeys.length > 0 ? `${prefixCls}-selected` : ''
+
+ return filterIcon ? cloneElement(filterIcon, {
+ title: locale.filterTitle,
+ className: classNames(filterIcon.className, {
+ [`${prefixCls}-icon`]: true,
+ }),
+ }) :
+ },
},
- handleMenuItemClick (info) {
- if (info.keyPath.length <= 1) {
- return
- }
- const keyPathOfSelectedItem = this.sKeyPathOfSelectedItem
- if (this.sSelectedKeys.indexOf(info.key) >= 0) {
- // deselect SubMenu child
- delete keyPathOfSelectedItem[info.key]
- } else {
- // select SubMenu child
- keyPathOfSelectedItem[info.key] = info.keyPath
- }
- this.setState({ keyPathOfSelectedItem })
- },
-
- renderFilterIcon () {
- const { column, locale, prefixCls } = this
- const filterIcon = column.filterIcon
- const dropdownSelectedClass = this.selectedKeys.length > 0 ? `${prefixCls}-selected` : ''
-
- return filterIcon ? cloneElement(filterIcon, {
- title: locale.filterTitle,
- className: classNames(filterIcon.className, {
- [`${prefixCls}-icon`]: true,
- }),
- }) :
- },
render () {
const { column, locale, prefixCls, dropdownPrefixCls, getPopupContainer } = this
// default multiple selection in filter dropdown
diff --git a/components/table/index.jsx b/components/table/index.jsx
index 3bb03589c..0a5bbd559 100644
--- a/components/table/index.jsx
+++ b/components/table/index.jsx
@@ -3,6 +3,7 @@ import T from './Table'
import { getOptionProps, getKey, getClass,
getStyle, getEvents, getSlotOptions, camelize, getSlots,
} from '../_util/props-util'
+
const Table = {
name: 'Table',
Column: T.Column,
@@ -61,13 +62,19 @@ const Table = {
},
},
render () {
- const { $listeners, $slots, normalize } = this
+ const { $listeners, $slots, normalize, $scopedSlots } = this
const props = getOptionProps(this)
const columns = props.columns ? this.updateColumns(props.columns) : normalize($slots.default)
+ let { title, footer } = props
+ const { title: slotTitle, footer: slotFooter } = $scopedSlots
+ title = title || slotTitle
+ footer = footer || slotFooter
const tProps = {
props: {
...props,
columns,
+ title,
+ footer,
},
on: $listeners,
}
diff --git a/components/table/interface.js b/components/table/interface.js
index 1d21f4411..e46a7a772 100644
--- a/components/table/interface.js
+++ b/components/table/interface.js
@@ -108,8 +108,8 @@ export const TableProps = {
useFixedHeader: PropTypes.bool,
bordered: PropTypes.bool,
showHeader: PropTypes.bool,
- footer: PropTypes.any,
- title: PropTypes.any,
+ footer: PropTypes.func,
+ title: PropTypes.func,
scroll: PropTypes.object,
childrenColumnName: PropTypes.string,
bodyStyle: PropTypes.any,
diff --git a/package-lock.json b/package-lock.json
index e1b9b05d3..dc96015fc 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14311,6 +14311,12 @@
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
"dev": true
},
+ "reqwest": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/reqwest/-/reqwest-2.0.5.tgz",
+ "integrity": "sha1-APsVrEkYxBnKgrQ/JMeIguZgOaE=",
+ "dev": true
+ },
"resolve": {
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz",
diff --git a/package.json b/package.json
index 81d5ce805..c5ae2dd47 100644
--- a/package.json
+++ b/package.json
@@ -105,6 +105,7 @@
"postcss-loader": "^2.1.2",
"pre-commit": "^1.2.2",
"querystring": "^0.2.0",
+ "reqwest": "^2.0.5",
"rimraf": "^2.6.2",
"rucksack-css": "^1.0.2",
"selenium-server": "^3.0.1",