add table demo

This commit is contained in:
tjz 2018-04-01 16:50:31 +08:00
parent 19ce259981
commit a79400fc1d
15 changed files with 972 additions and 208 deletions

View File

@ -1,5 +1,4 @@
import cloneDeep from 'lodash/cloneDeep'
import VcTable from '../vc-table' import VcTable from '../vc-table'
import classNames from 'classnames' import classNames from 'classnames'
import Pagination from '../pagination' import Pagination from '../pagination'
@ -33,10 +32,8 @@ function stopPropagation (e) {
} }
const defaultPagination = { const defaultPagination = {
on: { onChange: noop,
change: noop, onShowSizeChange: noop,
showSizeChange: noop,
},
} }
/** /**
@ -91,14 +88,13 @@ export default {
watch: { watch: {
pagination (val) { pagination (val) {
this.setState(previousState => { this.setState(previousState => {
const newPagination = mergeProps( const newPagination = {
defaultPagination, ...defaultPagination,
previousState.sPagination, ...previousState.sPagination,
val, ...val,
) }
newPagination.props = newPagination.props || {} newPagination.current = newPagination.current || 1
newPagination.props.current = newPagination.props.current || 1 newPagination.pageSize = newPagination.pageSize || 10
newPagination.props.pageSize = newPagination.props.pageSize || 10
return { sPagination: val !== false ? newPagination : emptyObject } return { sPagination: val !== false ? newPagination : emptyObject }
}) })
}, },
@ -176,17 +172,13 @@ export default {
getDefaultPagination (props) { getDefaultPagination (props) {
const pagination = props.pagination || {} const pagination = props.pagination || {}
pagination.props = pagination.props || {}
return this.hasPagination(props) return this.hasPagination(props)
? mergeProps( ? {
defaultPagination, ...defaultPagination,
pagination, ...pagination,
{ current: pagination.defaultCurrent || pagination.current || 1,
props: { pageSize: pagination.defaultPageSize || pagination.pageSize || 10,
current: pagination.props.defaultCurrent || pagination.props.current || 1, } : {}
pageSize: pagination.props.defaultPageSize || pagination.props.pageSize || 10,
},
}) : {}
}, },
onRow (record, index) { onRow (record, index) {
@ -345,7 +337,7 @@ export default {
if (this.getSortOrderColumns().length === 0) { if (this.getSortOrderColumns().length === 0) {
this.setState(newState) this.setState(newState)
} }
this.$emit('change', this.prepareParamsArguments({ this.$emit('change', ...this.prepareParamsArguments({
...this.$data, ...this.$data,
...newState, ...newState,
})) }))
@ -373,9 +365,8 @@ export default {
if (props.pagination) { if (props.pagination) {
// Reset current prop // Reset current prop
pagination.props = pagination.props || {} pagination.current = 1
pagination.props.current = 1 pagination.onChange(pagination.current)
pagination.on.change(pagination.current)
} }
const newState = { const newState = {
@ -395,23 +386,22 @@ export default {
} }
// Controlled current prop will not respond user interaction // Controlled current prop will not respond user interaction
if (typeof props.pagination === 'object' && props.pagination.props && 'current' in (props.pagination.props)) { if (typeof props.pagination === 'object' && 'current' in (props.pagination)) {
newState.sPagination = mergeProps(pagination, { newState.sPagination = {
props: { ...pagination,
current: this.sPagination.props.current, current: this.sPagination.current,
}, }
})
} }
this.setState(newState, () => { this.setState(newState, () => {
this.store.setState({ this.store.setState({
selectionDirty: false, selectionDirty: false,
}) })
this.$emit('change', this.prepareParamsArguments({ this.$emit('change', ...this.prepareParamsArguments({
...this.$data, ...this.$data,
selectionDirty: false, sSelectionDirty: false,
filters, sFilters: filters,
pagination, sPagination: pagination,
})) }))
}) })
}, },
@ -523,11 +513,11 @@ export default {
const props = this.$props const props = this.$props
const pagination = { ...this.sPagination } const pagination = { ...this.sPagination }
if (current) { if (current) {
pagination.props.current = current pagination.current = current
} else { } 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 = { const newState = {
sPagination: pagination, sPagination: pagination,
@ -535,23 +525,21 @@ export default {
// Controlled current prop will not respond user interaction // Controlled current prop will not respond user interaction
if (props.pagination && if (props.pagination &&
typeof props.pagination === 'object' && typeof props.pagination === 'object' &&
props.pagination.props && 'current' in (props.pagination)) {
'current' in (props.pagination.props)) { newState.sPagination = {
newState.sPagination = mergeProps(pagination, { ...pagination,
props: { current: this.sPagination.current,
current: this.sPagination.props.current, }
},
})
} }
this.setState(newState) this.setState(newState)
this.store.setState({ this.store.setState({
selectionDirty: false, selectionDirty: false,
}) })
this.$emit('change', this.prepareParamsArguments({ this.$emit('change', ...this.prepareParamsArguments({
...this.$data, ...this.$data,
selectionDirty: false, sSelectionDirty: false,
pagination, sPagination: pagination,
})) }))
}, },
@ -655,7 +643,7 @@ export default {
}, },
getMaxCurrent (total) { getMaxCurrent (total) {
const { current, pageSize } = this.sPagination.props const { current, pageSize } = this.sPagination
if ((current - 1) * pageSize >= total) { if ((current - 1) * pageSize >= total) {
return Math.floor((total - 1) / pageSize) + 1 return Math.floor((total - 1) / pageSize) + 1
} }
@ -738,17 +726,16 @@ export default {
handleShowSizeChange (current, pageSize) { handleShowSizeChange (current, pageSize) {
const pagination = this.sPagination const pagination = this.sPagination
pagination.on.showSizeChange(current, pageSize) pagination.onShowSizeChange(current, pageSize)
const nextPagination = mergeProps(pagination, { const nextPagination = {
props: { ...pagination,
pageSize, pageSize,
current, current,
}, }
})
this.setState({ sPagination: nextPagination }) this.setState({ sPagination: nextPagination })
this.$emit('change', this.prepareParamsArguments({ this.$emit('change', ...this.prepareParamsArguments({
...this.$data, ...this.$data,
pagination: nextPagination, sPagination: nextPagination,
})) }))
}, },
@ -759,25 +746,24 @@ export default {
} }
let size = 'default' let size = 'default'
const { sPagination: pagination } = this const { sPagination: pagination } = this
if (pagination.props && pagination.props.size) { if (pagination.size) {
size = pagination.props.size size = pagination.size
} else if (this.size === 'middle' || this.size === 'small') { } else if (this.size === 'middle' || this.size === 'small') {
size = 'small' size = 'small'
} }
const total = (pagination.props && pagination.props.total) || this.getLocalData().length const total = pagination.total || this.getLocalData().length
const { class: cls, style, on, props } = pagination const { class: cls, style, onChange, onShowSizeChange, ...restProps } = pagination // eslint-disable-line
const paginationProps = mergeProps({ const paginationProps = mergeProps({
key: 'pagination', key: 'pagination',
class: classNames(cls, `${this.prefixCls}-pagination`), class: classNames(cls, `${this.prefixCls}-pagination`),
props: { props: {
...props, ...restProps,
total, total,
size, size,
current: this.getMaxCurrent(total), current: this.getMaxCurrent(total),
}, },
style, style,
on: { on: {
...on,
change: this.handlePageChange, change: this.handlePageChange,
showSizeChange: this.handleShowSizeChange, showSizeChange: this.handleShowSizeChange,
}, },
@ -791,12 +777,10 @@ export default {
// Get pagination, filters, sorter // Get pagination, filters, sorter
prepareParamsArguments (state) { prepareParamsArguments (state) {
const pagination = cloneDeep(state.sPagination) const pagination = { ...state.sPagination }
// remove useless handle function in Table.onChange // remove useless handle function in Table.onChange
if (pagination.on) { delete pagination.onChange
delete pagination.on.change delete pagination.onShowSizeChange
delete pagination.on.showSizeChange
}
const filters = state.sFilters const filters = state.sFilters
const sorter = {} const sorter = {}
if (state.sSortColumn && state.sSortOrder) { if (state.sSortColumn && state.sSortOrder) {
@ -822,14 +806,14 @@ export default {
let data = this.getLocalData() let data = this.getLocalData()
let current let current
let pageSize let pageSize
const pagProps = this.sPagination.props || {} const sPagination = this.sPagination
// //
if (!this.hasPagination()) { if (!this.hasPagination()) {
pageSize = Number.MAX_VALUE pageSize = Number.MAX_VALUE
current = 1 current = 1
} else { } else {
pageSize = pagProps.pageSize pageSize = sPagination.pageSize
current = this.getMaxCurrent(pagProps.total || data.length) current = this.getMaxCurrent(sPagination.total || data.length)
} }
// //

View File

@ -0,0 +1,99 @@
<cn>
#### 远程加载数据
这个例子通过简单的 ajax 读取方式,演示了如何从服务端读取并展现数据,具有筛选、排序等功能以及页面 loading 效果。开发者可以自行接入其他数据处理方式。
另外,本例也展示了筛选排序功能如何交给服务端实现,列不需要指定具体的 `onFilter``sorter` 函数,而是在把筛选和排序的参数发到服务端来处理。
**注意,此示例使用 [模拟接口](https://randomuser.me),展示数据可能不准确,请打开网络面板查看请求。**
</cn>
<us>
#### 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.**
</us>
```html
<template>
<a-table :columns="columns"
:rowKey="record => record.registered"
:dataSource="data"
:pagination="pagination"
:loading="loading"
@change="handleTableChange"
>
<template slot="name" slot-scope="name">
{{name.first}} {{name.last}}
</template>
</a-table>
</template>
<script>
import reqwest from 'reqwest';
const columns = [{
title: 'Name',
dataIndex: 'name',
sorter: true,
width: '20%',
slotScopeName: 'name',
}, {
title: 'Gender',
dataIndex: 'gender',
filters: [
{ text: 'Male', value: 'male' },
{ text: 'Female', value: 'female' },
],
width: '20%',
}, {
title: 'Email',
dataIndex: 'email',
}];
export default {
mounted() {
this.fetch();
},
methods: {
handleTableChange (pagination, filters, sorter) {
console.log(pagination);
const pager = { ...this.pagination };
pager.current = pagination.current;
this.pagination = pager;
this.fetch({
results: pagination.pageSize,
page: pagination.current,
sortField: sorter.field,
sortOrder: sorter.order,
...filters,
});
},
fetch (params = {}) {
console.log('params:', params);
this.loading = true
reqwest({
url: 'https://randomuser.me/api',
method: 'get',
data: {
results: 10,
...params,
},
type: 'json',
}).then((data) => {
const pagination = { ...this.pagination };
// Read total count from server
// pagination.total = data.totalCount;
pagination.total = 200;
this.loading = false;
this.data = data.results;
this.pagination = pagination;
});
}
},
data() {
return {
data: [],
pagination: {},
loading: false,
columns,
}
}
}
</script>
```

View File

@ -0,0 +1,76 @@
<cn>
#### 基本用法
简单的表格,最后一列是各种操作。
</cn>
<us>
#### basic Usage
Simple table with actions.
</us>
```html
<template>
<a-table :columns="columns" :dataSource="data">
<template slot="name" slot-scope="text">
<a href="#">{{text}}</a>
</template>
<template slot="action" slot-scope="text, record">
<span>
<a href="#">Action 一 {{record.name}}</a>
<a-divider type="vertical" />
<a href="#">Delete</a>
<a-divider type="vertical" />
<a href="#" class="ant-dropdown-link">
More actions <a-icon type="down" />
</a>
</span>
</template>
</a-table>
</template>
<script>
const columns = [{
title: 'Name',
dataIndex: 'name',
key: 'name',
slotScopeName: 'name',
}, {
title: 'Age',
dataIndex: 'age',
key: 'age',
}, {
title: 'Address',
dataIndex: 'address',
key: 'address',
}, {
title: 'Action',
key: 'action',
slotScopeName: 'action',
}];
const data = [{
key: '1',
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park',
}, {
key: '2',
name: 'Jim Green',
age: 42,
address: 'London No. 1 Lake Park',
}, {
key: '3',
name: 'Joe Black',
age: 32,
address: 'Sidney No. 1 Lake Park',
}];
export default {
data() {
return {
data,
columns,
}
}
}
</script>
```

View File

@ -0,0 +1,76 @@
<cn>
#### 基本用法
简单的表格,最后一列是各种操作。
</cn>
<us>
#### basic Usage
Simple table with actions.
</us>
```html
<template>
<a-table :columns="columns" :dataSource="data">
<template slot="name" slot-scope="text">
<a href="#">{{text}}</a>
</template>
<template slot="action" slot-scope="text, record">
<span>
<a href="#">Action 一 {{record.name}}</a>
<a-divider type="vertical" />
<a href="#">Delete</a>
<a-divider type="vertical" />
<a href="#" class="ant-dropdown-link">
More actions <a-icon type="down" />
</a>
</span>
</template>
</a-table>
</template>
<script>
const columns = [{
title: 'Name',
dataIndex: 'name',
key: 'name',
slotScopeName: 'name',
}, {
title: 'Age',
dataIndex: 'age',
key: 'age',
}, {
title: 'Address',
dataIndex: 'address',
key: 'address',
}, {
title: 'Action',
key: 'action',
slotScopeName: 'action',
}];
const data = [{
key: '1',
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park',
}, {
key: '2',
name: 'Jim Green',
age: 42,
address: 'London No. 1 Lake Park',
}, {
key: '3',
name: 'Joe Black',
age: 32,
address: 'Sidney No. 1 Lake Park',
}];
export default {
data() {
return {
data,
columns,
}
}
}
</script>
```

View File

@ -0,0 +1,76 @@
<cn>
#### 基本用法
简单的表格,最后一列是各种操作。
</cn>
<us>
#### basic Usage
Simple table with actions.
</us>
```html
<template>
<a-table :columns="columns" :dataSource="data">
<template slot="name" slot-scope="text">
<a href="#">{{text}}</a>
</template>
<template slot="action" slot-scope="text, record">
<span>
<a href="#">Action 一 {{record.name}}</a>
<a-divider type="vertical" />
<a href="#">Delete</a>
<a-divider type="vertical" />
<a href="#" class="ant-dropdown-link">
More actions <a-icon type="down" />
</a>
</span>
</template>
</a-table>
</template>
<script>
const columns = [{
title: 'Name',
dataIndex: 'name',
key: 'name',
slotScopeName: 'name',
}, {
title: 'Age',
dataIndex: 'age',
key: 'age',
}, {
title: 'Address',
dataIndex: 'address',
key: 'address',
}, {
title: 'Action',
key: 'action',
slotScopeName: 'action',
}];
const data = [{
key: '1',
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park',
}, {
key: '2',
name: 'Jim Green',
age: 42,
address: 'London No. 1 Lake Park',
}, {
key: '3',
name: 'Joe Black',
age: 32,
address: 'Sidney No. 1 Lake Park',
}];
export default {
data() {
return {
data,
columns,
}
}
}
</script>
```

View File

@ -0,0 +1,76 @@
<cn>
#### 基本用法
简单的表格,最后一列是各种操作。
</cn>
<us>
#### basic Usage
Simple table with actions.
</us>
```html
<template>
<a-table :columns="columns" :dataSource="data">
<template slot="name" slot-scope="text">
<a href="#">{{text}}</a>
</template>
<template slot="action" slot-scope="text, record">
<span>
<a href="#">Action 一 {{record.name}}</a>
<a-divider type="vertical" />
<a href="#">Delete</a>
<a-divider type="vertical" />
<a href="#" class="ant-dropdown-link">
More actions <a-icon type="down" />
</a>
</span>
</template>
</a-table>
</template>
<script>
const columns = [{
title: 'Name',
dataIndex: 'name',
key: 'name',
slotScopeName: 'name',
}, {
title: 'Age',
dataIndex: 'age',
key: 'age',
}, {
title: 'Address',
dataIndex: 'address',
key: 'address',
}, {
title: 'Action',
key: 'action',
slotScopeName: 'action',
}];
const data = [{
key: '1',
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park',
}, {
key: '2',
name: 'Jim Green',
age: 42,
address: 'London No. 1 Lake Park',
}, {
key: '3',
name: 'Joe Black',
age: 32,
address: 'Sidney No. 1 Lake Park',
}];
export default {
data() {
return {
data,
columns,
}
}
}
</script>
```

View File

@ -0,0 +1,76 @@
<cn>
#### 基本用法
简单的表格,最后一列是各种操作。
</cn>
<us>
#### basic Usage
Simple table with actions.
</us>
```html
<template>
<a-table :columns="columns" :dataSource="data">
<template slot="name" slot-scope="text">
<a href="#">{{text}}</a>
</template>
<template slot="action" slot-scope="text, record">
<span>
<a href="#">Action 一 {{record.name}}</a>
<a-divider type="vertical" />
<a href="#">Delete</a>
<a-divider type="vertical" />
<a href="#" class="ant-dropdown-link">
More actions <a-icon type="down" />
</a>
</span>
</template>
</a-table>
</template>
<script>
const columns = [{
title: 'Name',
dataIndex: 'name',
key: 'name',
slotScopeName: 'name',
}, {
title: 'Age',
dataIndex: 'age',
key: 'age',
}, {
title: 'Address',
dataIndex: 'address',
key: 'address',
}, {
title: 'Action',
key: 'action',
slotScopeName: 'action',
}];
const data = [{
key: '1',
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park',
}, {
key: '2',
name: 'Jim Green',
age: 42,
address: 'London No. 1 Lake Park',
}, {
key: '3',
name: 'Joe Black',
age: 32,
address: 'Sidney No. 1 Lake Park',
}];
export default {
data() {
return {
data,
columns,
}
}
}
</script>
```

View File

@ -0,0 +1,76 @@
<cn>
#### 基本用法
简单的表格,最后一列是各种操作。
</cn>
<us>
#### basic Usage
Simple table with actions.
</us>
```html
<template>
<a-table :columns="columns" :dataSource="data">
<template slot="name" slot-scope="text">
<a href="#">{{text}}</a>
</template>
<template slot="action" slot-scope="text, record">
<span>
<a href="#">Action 一 {{record.name}}</a>
<a-divider type="vertical" />
<a href="#">Delete</a>
<a-divider type="vertical" />
<a href="#" class="ant-dropdown-link">
More actions <a-icon type="down" />
</a>
</span>
</template>
</a-table>
</template>
<script>
const columns = [{
title: 'Name',
dataIndex: 'name',
key: 'name',
slotScopeName: 'name',
}, {
title: 'Age',
dataIndex: 'age',
key: 'age',
}, {
title: 'Address',
dataIndex: 'address',
key: 'address',
}, {
title: 'Action',
key: 'action',
slotScopeName: 'action',
}];
const data = [{
key: '1',
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park',
}, {
key: '2',
name: 'Jim Green',
age: 42,
address: 'London No. 1 Lake Park',
}, {
key: '3',
name: 'Joe Black',
age: 32,
address: 'Sidney No. 1 Lake Park',
}];
export default {
data() {
return {
data,
columns,
}
}
}
</script>
```

View File

@ -0,0 +1,71 @@
<cn>
#### 带边框
添加表格边框线,页头和页脚。
</cn>
<us>
#### border, title and footer
Add border, title and footer for table.
</us>
```html
<template>
<a-table :columns="columns" :dataSource="data" bordered>
<template slot="name" slot-scope="text">
<a href="#">{{text}}</a>
</template>
<template slot="title" slot-scope="currentPageData">
Header
</template>
<template slot="footer" slot-scope="currentPageData">
Footer
</template>
</a-table>
</template>
<script>
const columns = [{
title: 'Name',
dataIndex: 'name',
slotScopeName: 'name',
}, {
title: 'Cash Assets',
className: 'column-money',
dataIndex: 'money',
}, {
title: 'Address',
dataIndex: 'address',
}];
const data = [{
key: '1',
name: 'John Brown',
money: '¥300,000.00',
address: 'New York No. 1 Lake Park',
}, {
key: '2',
name: 'Jim Green',
money: '¥1,256,000.00',
address: 'London No. 1 Lake Park',
}, {
key: '3',
name: 'Joe Black',
money: '¥120,000.00',
address: 'Sidney No. 1 Lake Park',
}];
export default {
data() {
return {
data,
columns,
}
}
}
</script>
<style>
th.column-money,
td.column-money {
text-align: right !important;
}
</style>
```

View File

@ -0,0 +1,143 @@
<cn>
#### 表格行/列合并
表头只支持列合并,使用 column 里的 colSpan 进行设置。
表格支持行/列合并,使用 render 里的单元格属性 colSpan 或者 rowSpan 设值为 0 时,设置的表格不会渲染。
</cn>
<us>
#### 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.
</us>
```html
<template>
<a-table :columns="columns" :dataSource="data" bordered>
<template slot="name" slot-scope="text">
<a href="#">{{text}}</a>
</template>
<template slot="action" slot-scope="text, record">
<span>
<a href="#">Action 一 {{record.name}}</a>
<a-divider type="vertical" />
<a href="#">Delete</a>
<a-divider type="vertical" />
<a href="#" class="ant-dropdown-link">
More actions <a-icon type="down" />
</a>
</span>
</template>
</a-table>
</template>
<script>
// In the fifth row, other columns are merged into first column
// by setting it's colSpan to be 0
const renderContent = (value, row, index) => {
const obj = {
children: value,
props: {},
};
if (index === 4) {
obj.props.colSpan = 0;
}
return obj;
};
const data = [{
key: '1',
name: 'John Brown',
age: 32,
tel: '0571-22098909',
phone: 18889898989,
address: 'New York No. 1 Lake Park',
}, {
key: '2',
name: 'Jim Green',
tel: '0571-22098333',
phone: 18889898888,
age: 42,
address: 'London No. 1 Lake Park',
}, {
key: '3',
name: 'Joe Black',
age: 32,
tel: '0575-22098909',
phone: 18900010002,
address: 'Sidney No. 1 Lake Park',
}, {
key: '4',
name: 'Jim Red',
age: 18,
tel: '0575-22098909',
phone: 18900010002,
address: 'London No. 2 Lake Park',
}, {
key: '5',
name: 'Jake White',
age: 18,
tel: '0575-22098909',
phone: 18900010002,
address: 'Dublin No. 2 Lake Park',
}];
export default {
data() {
const columns = [{
title: 'Name',
dataIndex: 'name',
customRender: (text, row, index) => {
if (index < 4) {
return <a href="#">{text}</a>;
}
return {
children: <a href="#">{text}</a>,
props: {
colSpan: 5,
},
};
},
}, {
title: 'Age',
dataIndex: 'age',
render: renderContent,
}, {
title: 'Home phone',
colSpan: 2,
dataIndex: 'tel',
customRender: (value, row, index) => {
const obj = {
children: value,
props: {},
};
if (index === 2) {
obj.props.rowSpan = 2;
}
// These two are merged into above cell
if (index === 3) {
obj.props.rowSpan = 0;
}
if (index === 4) {
obj.props.colSpan = 0;
}
return obj;
},
}, {
title: 'Phone',
colSpan: 0,
dataIndex: 'phone',
render: renderContent,
}, {
title: 'Address',
dataIndex: 'address',
render: renderContent,
}];
return {
data,
columns,
}
}
}
</script>
```

View File

@ -37,142 +37,139 @@ export default {
this.setNeverShown(column) this.setNeverShown(column)
}) })
}, },
watch: {
componentWillReceiveProps (nextProps) { 'column.fixed': function (val) {
const { column } = nextProps this.setNeverShown(this.column)
this.setNeverShown(column) },
const newState = {} column (val) {
if ('selectedKeys' in nextProps) { if ('filterDropdownVisible' in val) {
newState.selectedKeys = nextProps.selectedKeys this.sVisible = val.filterDropdownVisible
} }
if ('filterDropdownVisible' in column) { },
newState.visible = column.filterDropdownVisible selectedKeys (val) {
} this.sSelectedKeys = val
if (Object.keys(newState).length > 0) { },
this.setState(newState)
}
}, },
methods: { methods: {
setNeverShown (column) {
}, const rootNode = this.$el
const filterBelongToScrollBody = !!closest(rootNode, `.ant-table-scroll`)
setNeverShown (column) { if (filterBelongToScrollBody) {
const rootNode = this.$el // When fixed column have filters, there will be two dropdown menus
const filterBelongToScrollBody = !!closest(rootNode, `.ant-table-scroll`) // Filter dropdown menu inside scroll body should never be shown
if (filterBelongToScrollBody) { // To fix https://github.com/ant-design/ant-design/issues/5010 and
// When fixed column have filters, there will be two dropdown menus // https://github.com/ant-design/ant-design/issues/7909
// Filter dropdown menu inside scroll body should never be shown this.neverShown = !!column.fixed
// 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 ? (
<Checkbox checked={this.sSelectedKeys.indexOf(item.value.toString()) >= 0} />
) : (
<Radio checked={this.sSelectedKeys.indexOf(item.value.toString()) >= 0} />
)
return (
<MenuItem key={item.value}>
{input}
<span>{item.text}</span>
</MenuItem>
)
},
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 (
<SubMenu title={item.text} class={subMenuCls} key={item.value.toString()}>
{this.renderMenus(item.children)}
</SubMenu>
)
} }
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 ? (
<Checkbox checked={this.sSelectedKeys.indexOf(item.value.toString()) >= 0} />
) : (
<Radio checked={this.sSelectedKeys.indexOf(item.value.toString()) >= 0} />
)
return (
<MenuItem key={item.value}>
{input}
<span>{item.text}</span>
</MenuItem>
)
},
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 (
<SubMenu title={item.text} class={subMenuCls} key={item.value.toString()}>
{this.renderMenus(item.children)}
</SubMenu>
)
}
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,
}),
}) : <Icon title={locale.filterTitle} type='filter' class={dropdownSelectedClass} />
},
}, },
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,
}),
}) : <Icon title={locale.filterTitle} type='filter' class={dropdownSelectedClass} />
},
render () { render () {
const { column, locale, prefixCls, dropdownPrefixCls, getPopupContainer } = this const { column, locale, prefixCls, dropdownPrefixCls, getPopupContainer } = this
// default multiple selection in filter dropdown // default multiple selection in filter dropdown

View File

@ -3,6 +3,7 @@ import T from './Table'
import { getOptionProps, getKey, getClass, import { getOptionProps, getKey, getClass,
getStyle, getEvents, getSlotOptions, camelize, getSlots, getStyle, getEvents, getSlotOptions, camelize, getSlots,
} from '../_util/props-util' } from '../_util/props-util'
const Table = { const Table = {
name: 'Table', name: 'Table',
Column: T.Column, Column: T.Column,
@ -61,13 +62,19 @@ const Table = {
}, },
}, },
render () { render () {
const { $listeners, $slots, normalize } = this const { $listeners, $slots, normalize, $scopedSlots } = this
const props = getOptionProps(this) const props = getOptionProps(this)
const columns = props.columns ? this.updateColumns(props.columns) : normalize($slots.default) 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 = { const tProps = {
props: { props: {
...props, ...props,
columns, columns,
title,
footer,
}, },
on: $listeners, on: $listeners,
} }

View File

@ -108,8 +108,8 @@ export const TableProps = {
useFixedHeader: PropTypes.bool, useFixedHeader: PropTypes.bool,
bordered: PropTypes.bool, bordered: PropTypes.bool,
showHeader: PropTypes.bool, showHeader: PropTypes.bool,
footer: PropTypes.any, footer: PropTypes.func,
title: PropTypes.any, title: PropTypes.func,
scroll: PropTypes.object, scroll: PropTypes.object,
childrenColumnName: PropTypes.string, childrenColumnName: PropTypes.string,
bodyStyle: PropTypes.any, bodyStyle: PropTypes.any,

6
package-lock.json generated
View File

@ -14311,6 +14311,12 @@
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
"dev": true "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": { "resolve": {
"version": "1.1.7", "version": "1.1.7",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz",

View File

@ -105,6 +105,7 @@
"postcss-loader": "^2.1.2", "postcss-loader": "^2.1.2",
"pre-commit": "^1.2.2", "pre-commit": "^1.2.2",
"querystring": "^0.2.0", "querystring": "^0.2.0",
"reqwest": "^2.0.5",
"rimraf": "^2.6.2", "rimraf": "^2.6.2",
"rucksack-css": "^1.0.2", "rucksack-css": "^1.0.2",
"selenium-server": "^3.0.1", "selenium-server": "^3.0.1",