前言
在Vue的Ant-Design-Of-Vue-Table组件中,你可以对ant-design-of-vue-Table-pagination组件进行二次封装,这样可以减少页面代码重复,使页面代码更简洁、更容易操作。
1.新建一个table.js文件(Table+Pagination+查询按钮+重置按钮二次封装)
import { Table } from 'ant-design-vue'
import Vue from 'vue'
const componentName = 'my-table-option'
export default {
name: 'myTable',
props: Object.assign({}, Table.props, {
// 返回 Promise<{ currPage, totalCount, list: any[] }> 的获取数据的函数,用于内部管理数据加载
data: { type: Function },
// 查询条件
dataParameters: null,
// 是否开启:单击行则选中行
selectOnClick: { type: Boolean, default: true },
// 默认翻到第 1 页
pageNum: { type: Number, default: 1 },
// 默认分页大小 10 行
pageSize: { type: Number, default: 10 },
// 是否显示分页大小切换下拉框
showSizeChanger: { type: Boolean, default: true },
// 是否显示分页器
showPagination: { type: [String, Boolean], default: 'auto' },
pageURI: { type: Boolean, default: false },
bordered: { type: Boolean, default: true }
}),
data () {
return {
localLoading: false,
localDataSource: [],
localPagination: Object.assign({}, this.pagination),
localScroll: {},
// 表格列显示隐藏
filterValue: [],
filterShow: false,
fullDataSource: null, //合计
}
},
computed: {
// 判断是否在弹出框里,用于定义表格是否可以滚动
isInDialog () {
let parent = this.$parent
while (parent) {
if (parent.$options._componentTag === 'a-modal') {
return true
}
parent = parent.$parent
}
return false
},
localKeys () {
return [...Object.keys(this.$data), ...Object.keys(this._computedWatchers), ...Object.keys(this).filter(k => k.startsWith('local'))]
},
// 处理最大显示长度后的列
allColumns () {
let results = []
// 设置 scroll 属性后,需要设置所有列的 width 来避免表头和内容的错位。
// 对未设置 width 的 col 设置平均宽度
const fullWidth = this.localScroll.x || (this.$el || {}).offsetWidth - 85
const remainWidth = this.columns.reduce(
(remain, { width }) => width
? typeof width === 'string' && width.endsWith('%')
? remain - parseFloat(width) * fullWidth / 100
: remain - parseFloat(width)
: remain,
fullWidth
)
const noWidthColCount = this.columns.reduce((count, { width }) => width ? count : count + 1, 0)
const averageWidth = remainWidth / noWidthColCount
this.columns.forEach(col => !col.width && Vue.set(col, 'width', averageWidth))
results = this.columns.reduce((results, col) => {
// 超出后显示省略号
if (this.isDrag || col.key !== 'action') {
// 组件不支持排序省略一起使用,使用排序后,表头省略会失效
col.ellipsis = true
}
const result = Object.assign({}, col)
results.push(result)
return results
}, results)
return results
},
localColumns () {
return this.allColumns.filter(col => this.filterValue.includes(col.dataIndex || col.key || col.title))
},
// 不支持表格中有子表格,需要屏蔽
localComponents () {
const headerComponent = {}
if (!this.isDrag) return headerComponent
headerComponent.header = {}
headerComponent.header.cell = (h, props, children) => {
const { key, ...restProps } = props
const col = this.columns.find(col => {
const k = col.dataIndex || col.key
return k === key
})
if (!col) {
return h('th', { ...restProps }, [...children])
}
const dragProps = {
key: col.dataIndex || col.key,
class: 'table-draggable-handle',
attrs: {
w: 8,
x: col.width,
z: 1,
axis: 'x',
draggable: true,
resizable: false
},
on: {
dragging: (x) => {
col.width = Math.max(x, 35)
}
}
}
const drag = h('vue-draggable-resizable', { ...dragProps })
return <th {...restProps} title={col.title} width={col.width} class="resize-table-th">
{children}
{drag}
</th>
}
return headerComponent
}
},
watch: {
loading (val) {
this.localLoading = val
},
// 表格源数据
dataSource: {
handler (val) {
this.localDataSource = val
},
immediate: true
},
'localPagination.current' (val) {
this.pageURI && this.$router.push({
...this.$route,
params: Object.assign({}, this.$route.params, { pageNo: val })
})
},
pageNum (val) {
Object.assign(this.localPagination, { current: val })
},
pageSize (val) {
Object.assign(this.localPagination, { pageSize: val })
},
showSizeChanger (val) {
Object.assign(this.localPagination, { showSizeChanger: val })
},
scroll () {
this.calcLocalScroll()
},
},
created () {
// 判断表格使传进来得是获取数据得方法还是数据数组
if (this.data) {
const { pageNo } = this.$route.params
const localPageNum = this.pageURI ? (pageNo && parseInt(pageNo)) : this.pageNum
this.localPagination = ['auto', true].includes(this.showPagination)
? Object.assign({}, this.localPagination, {
showQuickJumper: true,
current: localPageNum,
pageSize: this.pageSize,
showSizeChanger: this.showSizeChanger,
pageSizeOptions: ['10', '20', '40']
})
: false
this.loadData()
} else {
this.localPagination = false
}
window.addEventListener('resize', this.calcLocalScroll)
},
mounted () {
setTimeout(() => {
// this.calcLocalScroll()
this.resetColumns()
})
},
destroyed () {
window.removeEventListener('resize', this.calcLocalScroll)
},
methods: {
/**
* 表格重新加载方法
* 如果参数为 true, 则强制刷新到第一页
* @param {boolean} bool
*/
refresh (bool = false, isSearch = true) {
!isSearch && this.resetColumns()
bool && (this.localPagination = Object.assign({}, {
current: 1,
pageSize: this.pageSize
}))
this.loadData()
},
/**
* 表格查询方法
* 如果参数为 true, 则强制刷新到第一页
* @param {boolean} bool
*/
serarch () {
this.loadData()
},
/**
* 加载数据方法
* @param {{ pageNum: number, pageSize: number }} pagination 分页选项器
* @param {{ [field: string]: string }} filters 过滤条件
* @param {{ field: string, order: 'asc' | 'desc' }} sorter 排序条件
*/
loadData (pagination, filters, sorter = {}) {
this.localLoading = true
let dataParameters = this.dataParameters;
let extraParams = {};
if (dataParameters != null) {
if (
typeof dataParameters != "object" ||
Array.isArray(dataParameters)
) {
extraParams = dataParameters;
} else {
for (let i in dataParameters) {
let source = extraParams[i];
if (typeof source == "function") {
extraParams[i] = dataParameters[i]();//函数,调用
} else {
extraParams[i] = dataParameters[i];
}
}
}
}
const result = this.data({
pageNum: (pagination && pagination.current) ||
this.showPagination && this.localPagination.current || this.pageNum,
pageSize: (pagination && pagination.pageSize) ||
this.showPagination && this.localPagination.pageSize || this.pageSize,
sidx: sorter.field,
order: sorter.order && sorter.order.slice(0, sorter.order.length - 3),
...filters,
...extraParams
})
// 对接自己的通用数据接口需要修改下方代码中的 r.pageNum, r.totalCount, r.list
// eslint-disable-next-line
if ((typeof result === 'object' || typeof result === 'function') && typeof result.then === 'function') {
result.then(r => {
r = r || { pageNum: 1, total: 0, list: [] }
this.localPagination = this.showPagination
? Object.assign({}, this.localPagination, {
showQuickJumper: true,
current: r.data.pageNum, // 返回结果中的当前分页数
total: r.data.total, // 返回结果中的总记录数
showSizeChanger: this.showSizeChanger,
pageSize: (pagination && pagination.pageSize) || this.localPagination.pageSize
})
: false
// 为防止删除数据后导致页面当前页面数据长度为 0 ,自动翻页到上一页
if (r.data.list.length === 0 && this.showPagination && this.localPagination.current > 1) {
this.localPagination.current--
this.loadData()
return
}
// 这里用于判断接口是否有返回 r.totalCount 且 this.showPagination = true 且 pageNo 和 pageSize 存在 且 totalCount 小于等于 pageNo * pageSize 的大小
// 当情况满足时,表示数据不满足分页大小,关闭 table 分页功能
try {
if ((['auto', true].includes(this.showPagination) && r.totalCount <= (r.pageNo * this.localPagination.pageSize))) {
this.localPagination.hideOnSinglePage = true
}
} catch (e) {
this.localPagination = false
}
console.log('查看新数据返回', r.data)
this.fullDataSource = r.data;
this.localDataSource = r.data.list // 返回结果中的数组数据
this.localLoading = false
})
}
},
/**
* 自定义行。可以配置表格行的相关事件,此处主要定义表格单击选中行,没有复选框或者单选框得表格可以屏蔽该功能
* @param {*} record
*/
localCustomRow (record) {
const rowCustomer = this.customRow ? this.customRow(record) : {}
if (!this.selectOnClick || !this.rowSelection) {
return rowCustomer
}
if (!rowCustomer.on) {
rowCustomer.on = {}
}
// 单击选中行需要判断是单选框还是多选框,表格多选或单选框得使用会在后续发文章补充。
const selectOnClickHandler = () => {
const { type, selectedRowKeys } = this.rowSelection
if (selectedRowKeys.includes(record[this.rowKey]) && !type) {
this.rowSelection.selections.splice(this.rowSelection.selections.findIndex(r => r === record), 1)
selectedRowKeys.splice(selectedRowKeys.findIndex(r => r === record[this.rowKey]), 1)
} else if (!type) {
this.rowSelection.selections.push(record)
selectedRowKeys.push(record[this.rowKey])
} else {
this.rowSelection.selectedRow = record
selectedRowKeys.splice(0, 1, record[this.rowKey])
}
}
if (rowCustomer.on.click) {
const originalClickHandler = rowCustomer.on.click
rowCustomer.on.click = e => {
originalClickHandler(e)
selectOnClickHandler(e, record)
}
} else {
rowCustomer.on.click = selectOnClickHandler
}
return rowCustomer
},
/**
* 表格列动态显示隐藏方法
*/
filter (checkedValues) {
this.filterValue = checkedValues
},
/**
* 表格列重置,主要使用在数据使用数据数组的表格
*/
resetColumns () {
this.filterValue = this.allColumns.map(col => col.dataIndex || col.key || col.title)
this.filterShow = !this.filterShow
},
},
// 渲染表格方法
render (h) {
const props = {}
// 表格属性
Object.keys(Table.props).forEach(k => {
const localKey = `local${k.substring(0, 1).toUpperCase()}${k.substring(1)}`
// if(k === 'columns'){}
if (this.localKeys.includes(localKey)) {
props[k] = this[localKey]
} else if (this[k] != null) {
props[k] = this[k]
}
})
//
const on = { ...this.$listeners }
this.data && (on.change = this.loadData)
let { title, footer } = this;
const {
title: slotTitle,
reduce: slotReduce,
} = this.$scopedSlots;
const footerFunction = () => { return slotReduce(this.fullDataSource); };
title = title || slotTitle;
footer = footer || footerFunction;
props.title = title;
props.footer = footer;
return (
<div class={`${componentName}-wrapper`} style="position: relative;">{[
h('a-table', {
props,
on,
scopedSlots: { ...this.$scopedSlots }
},
Object.keys(this.$slots).map(name => (
<template slot={name}>{this.$slots[name]}</template>
))
)]}
</div>
)
}
}
2.vue页面引入自定义封装方法(引入table.js文件)
<template>
<div>
<!-- 搜索 -->
<a-row>
<a-form :model="searchParam" ref="form">
<a-row>
<a-col span="8">
<span>航线代码:</span>
<a-input
style="width: 70%"
v-model="searchParam.routeCode"
placeholder="航线代码"
/>
</a-col>
<a-col span="8">
<span>航线名称:</span>
<a-input
style="width: 70%"
v-model="searchParam.routeName"
placeholder="航线名称"
/>
</a-col>
</a-row>
<br />
<a-row>
<a-col span="2">
<a-button type="primary" title="查询" @click="Search"
>查询</a-button
>
</a-col>
<a-col span="2">
<a-button title="重置" @click="query">重置</a-button>
</a-col>
<a-col span="2">
<a-popconfirm
title="确定删除?"
ok-text="确定"
cancel-text="取消"
@confirm="confirm"
@cancel="cancel"
>
<a-button title="删除" :disabled="!hasSelected" type="danger"
>删除</a-button
>
</a-popconfirm>
</a-col>
</a-row>
</a-form>
</a-row>
<a-row>
<!-- 表格 -->
<s-table
ref="table"
:columns="columns"
:data="loadData"
:dataParameters="searchParam"
>
<template slot="reduce" slot-scope="currentPageData">
共有{{ currentPageData && currentPageData.total }}条数据
</template>
</s-table>
</a-row>
</div>
</template>
<script>
// 引用数据请求方法
import api from '@/api'
// 引用封装的table和pagation方法
import STable from './tables'
export default {
data() {
return {
// table表头
columns: [
{
title: '类型',
dataIndex: 'type',
align: 'center',
width: '20%',
},
{
title: '航线名称',
dataIndex: 'routeName',
align: 'center',
width: '20%',
},
{
title: '航线代码',
dataIndex: 'routeCode',
align: 'center',
width: '20%',
},
{
title: '备注',
dataIndex: 'remark',
align: 'center',
width: '20%',
},
{
title: '操作',
width: '10%',
align: 'center',
scopedSlots: { customRender: 'operation' },
},
],
// 查询条件
searchParam: {
routeCode: null,
routeName: null,
},
}
},
methods: {
/*
* 获取数据的方法
* */
loadData(pagination) {
// 请求列表接口
return api.routesMaintenanceList({ ...pagination })
},
/*
* 重置按钮对应的方法
* */
query() {
this.refresh(true)
},
refresh(isBackToFirstPage = false) {
this.searchParam = {
routeCode: null,
routeName: null,
}
this.selectedRowKeys = []
this.$refs.table.refresh(isBackToFirstPage)
},
/*
* 查询
* */
Search() {
this.refresh(false)
}
},
}
</script>
<style scoped></style>