Commit 8aea275c by Sendya

refactor: s-table

parent 00be0c86
Table 重封装组件说明 Table 重封装组件说明
==== ====
封装说明 封装说明
---- ----
> 基础的使用方式与 API 与 [官方版(Table)](https://vuecomponent.github.io/ant-design-vue/components/table-cn/) 本一致,在其基础上,封装了加载数据的方法。 > 基础的使用方式与 API 与 [官方版(Table)](https://vuecomponent.github.io/ant-design-vue/components/table-cn/) 本一致,在其基础上,封装了加载数据的方法。
> >
> 你无需在你是用表格的页面进行分页逻辑处理,仅需向 Table 组件传递绑定 `:data="Promise"` 对象即可 > 你无需在你是用表格的页面进行分页逻辑处理,仅需向 Table 组件传递绑定 `:data="Promise"` 对象即可
`table`[@AraragiTsukihiz](https://github.com/araragitsukihiz) 完成封装 `table`[@AraragiTsukihiz](https://github.com/araragitsukihiz) 完成封装
例子1 例子1
---- ----
(基础使用) (基础使用)
```vue ```vue
<template> <template>
<s-table <s-table
ref="table" ref="table"
:rowKey="(record) => record.data.id" size="default"
size="default" :rowKey="(record) => record.data.id"
:columns="columns" :columns="columns"
:data="loadData" :data="loadData"
> :rowSelection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }"
</s-table> >
</template> </s-table>
</template>
<script>
import STable from '@/components/table/' <script>
import STable from '@/components/table/'
export default {
components: { export default {
STable components: {
}, STable
data() { },
return { data() {
columns: [ return {
{ columns: [
title: '规则编号', {
dataIndex: 'no' title: '规则编号',
}, dataIndex: 'no'
{ },
title: '描述', {
dataIndex: 'description' title: '描述',
}, dataIndex: 'description'
{ },
title: '服务调用次数', {
dataIndex: 'callNo', title: '服务调用次数',
sorter: true, dataIndex: 'callNo',
needTotal: true, sorter: true,
customRender: (text) => text + ' 次' needTotal: true,
}, customRender: (text) => text + ' 次'
{ },
title: '状态', {
dataIndex: 'status', title: '状态',
needTotal: true dataIndex: 'status',
}, needTotal: true
{ },
title: '更新时间', {
dataIndex: 'updatedAt', title: '更新时间',
sorter: true dataIndex: 'updatedAt',
} sorter: true
], }
// 查询条件参数 ],
queryParam: {}, // 查询条件参数
// 加载数据方法 必须为 Promise 对象 queryParam: {},
loadData: parameter => { // 加载数据方法 必须为 Promise 对象
return this.$http.get('/service', { loadData: parameter => {
params: Object.assign(parameter, this.queryParam) return this.$http.get('/service', {
}).then(res => { params: Object.assign(parameter, this.queryParam)
return res.result }).then(res => {
}) return res.result
}, })
} },
} selectedRowKeys: [],
} selectedRows: []
</script> }
},
``` methods: {
onSelectChange (selectedRowKeys, selectedRows) {
this.selectedRowKeys = selectedRowKeys
this.selectedRows = selectedRows
例子2 }
---- }
}
(简单的表格,最后一列是各种操作) </script>
```vue ```
<template>
<s-table
ref="table"
size="default" 例子2
:columns="columns" ----
:data="loadData"
> (简单的表格,最后一列是各种操作)
<span slot="action" slot-scope="text, record">
<a>编辑</a> ```vue
<a-divider type="vertical"/> <template>
<a-dropdown> <s-table
<a class="ant-dropdown-link"> ref="table"
更多 <a-icon type="down"/> size="default"
</a> :columns="columns"
<a-menu slot="overlay"> :data="loadData"
<a-menu-item> >
<a href="javascript:;">1st menu item</a> <span slot="action" slot-scope="text, record">
</a-menu-item> <a>编辑</a>
<a-menu-item> <a-divider type="vertical"/>
<a href="javascript:;">2nd menu item</a> <a-dropdown>
</a-menu-item> <a class="ant-dropdown-link">
<a-menu-item> 更多 <a-icon type="down"/>
<a href="javascript:;">3rd menu item</a> </a>
</a-menu-item> <a-menu slot="overlay">
</a-menu> <a-menu-item>
</a-dropdown> <a href="javascript:;">1st menu item</a>
</span> </a-menu-item>
</s-table> <a-menu-item>
</template> <a href="javascript:;">2nd menu item</a>
</a-menu-item>
<script> <a-menu-item>
import STable from '@/components/table/' <a href="javascript:;">3rd menu item</a>
</a-menu-item>
export default { </a-menu>
components: { </a-dropdown>
STable </span>
}, </s-table>
data() { </template>
return {
columns: [ <script>
{ import STable from '@/components/table/'
title: '规则编号',
dataIndex: 'no' export default {
}, components: {
{ STable
title: '描述', },
dataIndex: 'description' data() {
}, return {
{ columns: [
title: '服务调用次数', {
dataIndex: 'callNo', title: '规则编号',
}, dataIndex: 'no'
{ },
title: '状态', {
dataIndex: 'status', title: '描述',
}, dataIndex: 'description'
{ },
title: '更新时间', {
dataIndex: 'updatedAt', title: '服务调用次数',
}, dataIndex: 'callNo',
{ },
table: '操作', {
dataIndex: 'action', title: '状态',
scopedSlots: {customRender: 'action'}, dataIndex: 'status',
} },
], {
// 查询条件参数 title: '更新时间',
queryParam: {}, dataIndex: 'updatedAt',
// 加载数据方法 必须为 Promise 对象 },
loadData: parameter => { {
return this.$http.get('/service', { table: '操作',
params: Object.assign(parameter, this.queryParam) dataIndex: 'action',
}).then(res => { scopedSlots: {customRender: 'action'},
return res.result }
}) ],
}, // 查询条件参数
} queryParam: {},
}, // 加载数据方法 必须为 Promise 对象
methods: { loadData: parameter => {
edit(row) { return this.$http.get('/service', {
// axios 发送数据到后端 修改数据成功后 params: Object.assign(parameter, this.queryParam)
// 调用 refresh() 重新加载列表数据 }).then(res => {
// 这里 setTimeout 模拟发起请求的网络延迟.. return res.result
setTimeout(() => { })
this.$refs.table.refresh() },
}, 1500) }
},
} methods: {
} edit(row) {
} // axios 发送数据到后端 修改数据成功后
</script> // 调用 refresh() 重新加载列表数据
``` // 这里 setTimeout 模拟发起请求的网络延迟..
setTimeout(() => {
this.$refs.table.refresh()
}, 1500)
内置方法
---- }
}
通过 `this.$refs.table` 调用 }
</script>
`this.$refs.table.refresh()` 刷新列表 (用户新增/修改数据后,重载列表数据) ```
> 注意:要调用 `refresh()` 需要给表格组件设定 `ref` 值
内置方法
----
注意事项
---- 通过 `this.$refs.table` 调用
> 你可能需要为了与后端提供的接口返回结果一致而去修改以下代码: `this.$refs.table.refresh()` 刷新列表 (用户新增/修改数据后,重载列表数据)
(需要注意的是,这里的修改是全局性的,意味着整个项目所有使用该 table 组件都需要遵守这个返回结果定义的字段。)
> 注意:要调用 `refresh()` 需要给表格组件设定 `ref` 值
修改 `@/components/table/index.js` 第 106 行起
内置属性
----
```javascript > 除去 `a-table` 自带属性外,还而外提供了 `alert` `props` 属性
result.then(r => { ```javascript
this.localPagination = Object.assign({}, this.localPagination, { alert: {
current: r.pageNo, // 返回结果中的当前分页数 show: Boolean,
total: r.totalCount, // 返回结果中的总记录数 clear: [Function, Boolean]
showSizeChanger: this.showSizeChanger, }
pageSize: (pagination && pagination.pageSize) || ```
this.localPagination.pageSize
}); 注意事项
----
!r.totalCount && ['auto', false].includes(this.showPagination) && (this.localPagination = false)
this.localDataSource = r.data; // 返回结果中的数组数据 > 你可能需要为了与后端提供的接口返回结果一致而去修改以下代码:
this.localLoading = false (需要注意的是,这里的修改是全局性的,意味着整个项目所有使用该 table 组件都需要遵守这个返回结果定义的字段。)
});
``` 修改 `@/components/table/index.js` 第 124 行起
返回 JSON 例子:
```json
{
"message": "", ```javascript
"result": { result.then(r => {
"data": [{ this.localPagination = Object.assign({}, this.localPagination, {
id: 1, current: r.pageNo, // 返回结果中的当前分页数
cover: 'https://gw.alipayobjects.com/zos/rmsportal/WdGqmHpayyMjiEhcKoVE.png', total: r.totalCount, // 返回结果中的总记录数
title: 'Alipay', showSizeChanger: this.showSizeChanger,
description: '那是一种内在的东西, 他们到达不了,也无法触及的', pageSize: (pagination && pagination.pageSize) ||
status: 1, this.localPagination.pageSize
updatedAt: '2018-07-26 00:00:00' })
},
{ // 为防止删除数据后导致页面当前页面数据长度为 0 ,自动翻页到上一页
id: 2, if (r.data.length == 0 && this.localPagination.current != 1) {
cover: 'https://gw.alipayobjects.com/zos/rmsportal/zOsKZmFRdUtvpqCImOVY.png', this.localPagination.current--
title: 'Angular', this.loadData()
description: '希望是一个好东西,也许是最好的,好东西是不会消亡的', return
status: 1, }
updatedAt: '2018-07-26 00:00:00'
}, // 这里用于判断接口是否有返回 r.totalCount 或 this.showPagination = false
{ // 当情况满足时,表示数据不满足分页大小,关闭 table 分页功能
id: 3, !r.totalCount && ['auto', false].includes(this.showPagination) && (this.localPagination = false)
cover: 'https://gw.alipayobjects.com/zos/rmsportal/dURIMkkrRFpPgTuzkwnB.png', this.localDataSource = r.data // 返回结果中的数组数据
title: 'Ant Design', this.localLoading = false
description: '城镇中有那么多的酒馆,她却偏偏走进了我的酒馆', });
status: 1, ```
updatedAt: '2018-07-26 00:00:00' 返回 JSON 例子:
}, ```json
{ {
id: 4, "message": "",
cover: 'https://gw.alipayobjects.com/zos/rmsportal/sfjbOqnsXXJgNCjCzDBL.png', "result": {
title: 'Ant Design Pro', "data": [{
description: '那时候我只会想自己想要什么,从不想自己拥有什么', id: 1,
status: 1, cover: 'https://gw.alipayobjects.com/zos/rmsportal/WdGqmHpayyMjiEhcKoVE.png',
updatedAt: '2018-07-26 00:00:00' title: 'Alipay',
}, description: '那是一种内在的东西, 他们到达不了,也无法触及的',
{ status: 1,
id: 5, updatedAt: '2018-07-26 00:00:00'
cover: 'https://gw.alipayobjects.com/zos/rmsportal/siCrBXXhmvTQGWPNLBow.png', },
title: 'Bootstrap', {
description: '凛冬将至', id: 2,
status: 1, cover: 'https://gw.alipayobjects.com/zos/rmsportal/zOsKZmFRdUtvpqCImOVY.png',
updatedAt: '2018-07-26 00:00:00' title: 'Angular',
}, description: '希望是一个好东西,也许是最好的,好东西是不会消亡的',
{ status: 1,
id: 6, updatedAt: '2018-07-26 00:00:00'
cover: 'https://gw.alipayobjects.com/zos/rmsportal/ComBAopevLwENQdKWiIn.png', },
title: 'Vue', {
description: '生命就像一盒巧克力,结果往往出人意料', id: 3,
status: 1, cover: 'https://gw.alipayobjects.com/zos/rmsportal/dURIMkkrRFpPgTuzkwnB.png',
updatedAt: '2018-07-26 00:00:00' title: 'Ant Design',
} description: '城镇中有那么多的酒馆,她却偏偏走进了我的酒馆',
], status: 1,
"pageSize": 10, updatedAt: '2018-07-26 00:00:00'
"pageNo": 0, },
"totalPage": 6, {
"totalCount": 57 id: 4,
}, cover: 'https://gw.alipayobjects.com/zos/rmsportal/sfjbOqnsXXJgNCjCzDBL.png',
"status": 200, title: 'Ant Design Pro',
"timestamp": 1534955098193 description: '那时候我只会想自己想要什么,从不想自己拥有什么',
} status: 1,
``` updatedAt: '2018-07-26 00:00:00'
},
{
id: 5,
更新时间 cover: 'https://gw.alipayobjects.com/zos/rmsportal/siCrBXXhmvTQGWPNLBow.png',
---- title: 'Bootstrap',
description: '凛冬将至',
status: 1,
updatedAt: '2018-07-26 00:00:00'
},
{
id: 6,
cover: 'https://gw.alipayobjects.com/zos/rmsportal/ComBAopevLwENQdKWiIn.png',
title: 'Vue',
description: '生命就像一盒巧克力,结果往往出人意料',
status: 1,
updatedAt: '2018-07-26 00:00:00'
}
],
"pageSize": 10,
"pageNo": 0,
"totalPage": 6,
"totalCount": 57
},
"status": 200,
"timestamp": 1534955098193
}
```
更新时间
----
该文档最后更新于: 2018-10-31 PM 08:15 该文档最后更新于: 2018-10-31 PM 08:15
\ No newline at end of file
import T from 'ant-design-vue/es/table/Table' import T from 'ant-design-vue/es/table/Table'
import get from 'lodash.get' import get from 'lodash.get'
export default { export default {
data() { data() {
return { return {
...@@ -38,8 +39,14 @@ export default { ...@@ -38,8 +39,14 @@ export default {
type: String, type: String,
default: 'default' default: 'default'
}, },
/**
* {
* show: true,
* clear: Function
* }
*/
alert: { alert: {
type: Object, type: [Object, Boolean],
default: null default: null
}, },
/** @Deprecated */ /** @Deprecated */
...@@ -57,7 +64,7 @@ export default { ...@@ -57,7 +64,7 @@ export default {
name: this.$route.name, name: this.$route.name,
params: Object.assign({}, this.$route.params, { params: Object.assign({}, this.$route.params, {
pageNo: val pageNo: val
}), })
}) })
}, },
pageNum(val) { pageNum(val) {
...@@ -66,13 +73,11 @@ export default { ...@@ -66,13 +73,11 @@ export default {
}) })
}, },
pageSize(val) { pageSize(val) {
console.log('pageSize:', val)
Object.assign(this.localPagination, { Object.assign(this.localPagination, {
pageSize: val pageSize: val
}) })
}, },
showSizeChanger(val) { showSizeChanger(val) {
console.log('showSizeChanger', val)
Object.assign(this.localPagination, { Object.assign(this.localPagination, {
showSizeChanger: val showSizeChanger: val
}) })
...@@ -112,7 +117,7 @@ export default { ...@@ -112,7 +117,7 @@ export default {
) )
) )
// 对接自己的通用数据接口需要修改下方代码中的 r.pageNo, r.totalCount, r.data // 对接自己的通用数据接口需要修改下方代码中的 r.pageNo, r.totalCount, r.data
if (result instanceof Promise) { if (result instanceof Promise) {
result.then(r => { result.then(r => {
this.localPagination = Object.assign({}, this.localPagination, { this.localPagination = Object.assign({}, this.localPagination, {
...@@ -122,7 +127,7 @@ export default { ...@@ -122,7 +127,7 @@ export default {
pageSize: (pagination && pagination.pageSize) || pageSize: (pagination && pagination.pageSize) ||
this.localPagination.pageSize this.localPagination.pageSize
}) })
// 为防止删除数据后导致页面当前页面数据长度为 0 ,自动翻页到上一页 // 为防止删除数据后导致页面当前页面数据长度为 0 ,自动翻页到上一页
if (r.data.length == 0 && this.localPagination.current != 1) { if (r.data.length == 0 && this.localPagination.current != 1) {
this.localPagination.current-- this.localPagination.current--
...@@ -130,7 +135,7 @@ export default { ...@@ -130,7 +135,7 @@ export default {
return return
} }
// 这里用于判断接口是否有返回 r.totalCount 或 this.showPagination = false // 这里用于判断接口是否有返回 r.totalCount 或 this.showPagination = false
// 当情况满足时,表示数据不满足分页大小,关闭 table 分页功能 // 当情况满足时,表示数据不满足分页大小,关闭 table 分页功能
!r.totalCount && ['auto', false].includes(this.showPagination) && (this.localPagination = false) !r.totalCount && ['auto', false].includes(this.showPagination) && (this.localPagination = false)
this.localDataSource = r.data // 返回结果中的数组数据 this.localDataSource = r.data // 返回结果中的数组数据
...@@ -142,15 +147,20 @@ export default { ...@@ -142,15 +147,20 @@ export default {
const totalList = [] const totalList = []
columns && columns instanceof Array && columns.forEach(column => { columns && columns instanceof Array && columns.forEach(column => {
if (column.needTotal) { if (column.needTotal) {
totalList.push({ ...column, totalList.push({
...column,
total: 0 total: 0
}) })
} }
}) })
return totalList return totalList
}, },
/**
* 用于更新已选中的列表数据 total 统计
* @param selectedRowKeys
* @param selectedRows
*/
updateSelect(selectedRowKeys, selectedRows) { updateSelect(selectedRowKeys, selectedRows) {
this.selectedRowKeys = selectedRowKeys
this.selectedRows = selectedRows this.selectedRows = selectedRows
const list = this.needTotalList const list = this.needTotalList
this.needTotalList = list.map(item => { this.needTotalList = list.map(item => {
...@@ -162,123 +172,91 @@ export default { ...@@ -162,123 +172,91 @@ export default {
}, 0) }, 0)
} }
}) })
// this.$emit('change', selectedRowKeys, selectedRows)
},
updateEdit() {
this.selectedRows = []
}, },
onClearSelected() { /**
this.selectedRowKeys = [] * 清空 table 已选中项
this.updateSelect([], []) */
clearSelected () {
if (this.rowSelection) {
this.rowSelection.onChange([], [])
this.updateSelect([], [])
}
}, },
renderMsg(h) { /**
const _vm = this * 处理交给 table 使用者去处理 clear 事件时,内部选中统计同时调用
const d = [] * @param callback
// 构建 已选择 * @returns {*}
d.push( */
h('span', { renderClear (callback) {
style: { return (
marginRight: '12px' <a style="margin-left: 24px" onClick={() => {
} callback()
}, ['已选择 ', h('a', { this.clearSelected()
style: { }}>清空</a>
fontWeight: 600
}
}, this.selectedRows.length)])
) )
},
// 构建 列统计 renderAlert () {
this.needTotalList.map(item => { // 绘制统计列数据
d.push(h('span', { const needTotalItems = this.needTotalList.map((item) => {
style: { return (<span style="margin-right: 12px">
marginRight: '12px' {item.title}总计 <a style="font-weight: 600">{!item.customRender ? item.total : item.customRender(item.total)}</a>
} </span>)
},
[
`${ item.title }总计 `,
h('a', {
style: {
fontWeight: 600
}
}, `${ !item.customRender ? item.total : item.customRender(item.total) }`)
]))
}) })
// 构建 清空选择 // 绘制 清空 按钮
d.push(h('a', { const clearItem = (typeof this.alert.clear === 'boolean' && this.alert.clear) ? (
style: { this.renderClear(this.clearSelected)
marginLeft: '24px' ) : (this.alert !== null && typeof this.alert.clear === 'function') ? (
}, this.renderClear(this.alert.clear)
on: { ) : null
click: _vm.onClearSelected
}
}, '清空'))
return d // 绘制 alert 组件
}, return (
renderAlert(h) { <a-alert showIcon={true} style="margin-bottom: 16px">
return h('span', { <template slot="message">
slot: 'message' <span style="margin-right: 12px">已选择: <a style="font-weight: 600">{this.selectedRows.length}</a></span>
}, this.renderMsg(h)) {needTotalItems}
}, {clearItem}
</template>
</a-alert>
)
}
}, },
render(h) { render() {
const _vm = this const props = {}
const localKeys = Object.keys(this.$data)
const props = {}, const showAlert = (typeof this.alert === 'object' && this.alert !== null && this.alert.show) || this.alert
localKeys = Object.keys(this.$data)
Object.keys(T.props).forEach(k => { Object.keys(T.props).forEach(k => {
const localKey = `local${k.substring(0,1).toUpperCase()}${k.substring(1)}` const localKey = `local${k.substring(0, 1).toUpperCase()}${k.substring(1)}`
if (localKeys.includes(localKey)) { if (localKeys.includes(localKey)) {
return props[k] = _vm[localKey] return props[k] = this[localKey]
} }
return props[k] = _vm[k] if (showAlert && k === 'rowSelection') {
}) // 重新绑定 rowSelection 事件
return props[k] = {
selectedRowKeys: this[k].selectedRowKeys,
// 显示信息提示 onChange: (selectedRowKeys, selectedRows) => {
if (this.showAlertInfo) { this.updateSelect(selectedRowKeys, selectedRows)
this[k].onChange(selectedRowKeys, selectedRows)
props.rowSelection = { }
selectedRowKeys: this.selectedRowKeys,
onChange: (selectedRowKeys, selectedRows) => {
_vm.updateSelect(selectedRowKeys, selectedRows)
_vm.$emit('onSelect', { selectedRowKeys: selectedRowKeys, selectedRows: selectedRows })
} }
} }
return props[k] = this[k]
})
return h('div', {}, [ const table = (
h('a-alert', { <a-table {...{ props, scopedSlots: {...this.$scopedSlots}}} onChange={this.loadData}>
style: { {this.$slots.default}
marginBottom: '16px' </a-table>
}, )
props: {
type: 'info',
showIcon: true
}
}, [_vm.renderAlert(h)]),
h('a-table', {
tag: 'component',
attrs: props,
on: {
change: _vm.loadData
},
scopedSlots: this.$scopedSlots
}, this.$slots.default)
])
}
return h('a-table', {
tag: 'component',
attrs: props,
on: {
change: _vm.loadData
},
scopedSlots: this.$scopedSlots
}, this.$slots.default)
return (
<div class="table-wrapper">
{ showAlert ? this.renderAlert() : null }
{ table }
</div>
)
} }
} }
\ No newline at end of file
...@@ -80,8 +80,8 @@ ...@@ -80,8 +80,8 @@
size="default" size="default"
:columns="columns" :columns="columns"
:data="loadData" :data="loadData"
:showAlertInfo="true" :alert="{ show: true, clear: () => { this.selectedRowKeys = [] } }"
@onSelect="onChange" :rowSelection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }"
> >
<span slot="action" slot-scope="text, record"> <span slot="action" slot-scope="text, record">
<template v-if="$auth('table.update')"> <template v-if="$auth('table.update')">
...@@ -271,11 +271,10 @@ ...@@ -271,11 +271,10 @@
handleOk () { handleOk () {
}, },
onChange (row) {
this.selectedRowKeys = row.selectedRowKeys
this.selectedRows = row.selectedRows
console.log(this.$refs.table) onSelectChange (selectedRowKeys, selectedRows) {
this.selectedRowKeys = selectedRowKeys
this.selectedRows = selectedRows
}, },
toggleAdvanced () { toggleAdvanced () {
this.advanced = !this.advanced this.advanced = !this.advanced
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment