表格组件
说明:el-table的二次封装,使用scheme配置的方式设置表格字段。
1.实现效果,与el-table一致


2.类型文件types.d.ts
yaml
import type { PaginationProps, TableColumnCtx, TableProps } from 'element-plus'
import { Component } from 'vue'
export interface TableColumnType extends TableColumnCtx<any> {
defaultSlot?: typeof Component
headerSlot?: typeof Component
children?: TableColumnType[]
}
export interface PaginationType extends Partial<PaginationProps> {
align?: 'left' | 'center' | 'right'
total: number
defaultSlot?: typeof Component
}
export interface VTableProps extends TableProps<any> {
columns: TableColumnType[]
pagination?: PaginationType
}
export type TableEventsType = {
select: [selection: any, row: any]
'select-all': [selection: any]
'selection-change': [selection: any]
'cell-mouse-enter': [row: any, column: any, cell: any, event: Event]
'cell-mouse-leave': [row: any, column: any, cell: any, event: Event]
'cell-click': [row: any, column: any, cell: any, event: Event]
'cell-dblclick': [row: any, column: any, cell: any, event: Event]
'cell-contextmenu': [row: any, column: any, cell: any, event: Event]
'row-click': [row: any, column: any, event: Event]
'row-contextmenu': [row: any, column: any, event: Event]
'row-dblclick': [row: any, column: any, event: Event]
'header-click': [column: any, event: Event]
'header-contextmenu': [column: any, event: Event]
'sort-change': [{ column: any; prop: string; order: string }]
'filter-change': [{ key: string }, filters: any[]]
'current-change': [currentRow: any, oldCurrentRow: any]
'header-draged': [newWidth: number, oldWidth: number, column: any, event: Event]
'expand-change': [row: any, expandedRows: any[] | boolean]
}
// 分页中事件的回调函数
type PaginationCallFunc = (value: number) => void
// 分页组件emit出事件,因pagination中事件与table中事件重名,故重命名page-xx
export type PaginationEventsType = {
'page-size-change': [PaginationCallFunc]
'page-current-change': [PaginationCallFunc]
'page-prev-click': [PaginationCallFunc]
'page-next-click': [PaginationCallFunc]
}
// table+pagination emit出事件
export type VTableEmitsType = TableEventsType & PaginationEventsType
3.el-table-column 封装 VTableColumn.vue
xml
<template>
<el-table-column v-bind="props">
<!-- 设置el-table-column插槽,可以在scheme中配置对应的插槽内容 -->
<template #default="scope" v-if="defaultSlot">
<component v-bind="scope" :is="defaultSlot"></component>
</template>
<template #header="scope" v-if="headerSlot">
<component v-bind="scope" :is="headerSlot"></component>
</template>
<!-- 处理嵌套的多级表头 -->
<template v-if="children && children.length">
<v-table-column v-bind="item" v-for="(item, index) in children" :key="index"></v-table-column>
</template>
</el-table-column>
</template>
<script setup lang="ts">
import type { TableColumnType } from './types'
const props = defineProps<TableColumnType>()
</script>
<style scoped></style>
4.el-table封装VTable.vue
xml
<template>
<el-table ref="tableRef" v-bind="props" v-on="events" style="width: 100%">
<v-table-column
v-for="(column, index) in props.columns"
:key="index"
v-bind="setColumnDefault(column)"
></v-table-column>
<!-- 设置el-table默认插槽 -->
<slot></slot>
<!-- 设置el-table的empty和append插槽 -->
<template #empty>
<slot name="empty"></slot>
</template>
<template #append>
<slot name="append"></slot>
</template>
</el-table>
<div :class="['flex p-2', paginationClass]" v-if="isDefined(pagination)">
<el-pagination v-bind="pagination" v-on="pageEvents">
<template #default="scope" v-if="pagination.defaultSlot">
<component v-bind="scope" :is="pagination.defaultSlot"></component>
</template>
</el-pagination>
</div>
</template>
<script lang="ts" setup>
import { isDefined } from '@vueuse/core'
import type { VTableEmitsType, VTableProps } from './types'
import VTableColumn from './VTableColumn.vue'
import { exposeEventsUtils, forwardEventsUtils } from '@/utils/format'
import type { TableColumnCtx } from 'element-plus'
// 接收传入的数据
const props = withDefaults(defineProps<VTableProps>(), {
pagination: () => ({
align: 'right',
size: 'default',
small: false,
background: false,
layout: 'total, sizes, prev, pager, next, jumper',
pageSizes: [10, 20, 30, 40, 50, 100],
total: 0
}),
stripe: false,
border: true,
size: 'default',
fit: true,
showHeader: true,
highlightCurrentRow: false,
emptyText: 'No data',
defaultExpandAll: false,
tooltipEffect: 'dark',
showSummary: false,
flexible: false,
selectOnIndeterminate: true,
indent: 16,
tableLayout: 'fixed',
scrollbarAlwaysOn: false
})
const tableRef = ref()
// 传出el-table事件,在封装的组件上直接使用即可
const emits = defineEmits<VTableEmitsType>()
// el-table所有事件名称
const eventsName = [
'select',
'select-all',
'selection-change',
'cell-mouse-enter',
'cell-mouse-leave',
'cell-contextmenu',
'cell-click',
'cell-dblclick',
'row-click',
'row-contextmenu',
'row-dblclick',
'header-click',
'header-contextmenu',
'sort-change',
'filter-change',
'current-change',
'header-dragend',
'expand-change'
]
// el-pagination分页事件名称
const pageEventsName = ['size-change', 'current-change', 'prev-click', 'next-click']
// el-table所有方法名称,可以在封装的组件上直接使用
const exposeEvents = [
'clearSelection',
'getSelectionRows',
'toggleRowSelection',
'toggleAllSelection',
'toggleRowExpansion',
'setCurrentRow',
'clearSort',
'clearFilter',
'doLayout',
'sort',
'scrollTo',
'setScrollTop',
'setScrollLeft'
]
// 获取所有事件集合为events对象
const events = forwardEventsUtils(emits, eventsName)
// 获取所有分页事件集合为pageEvents对象
const pageEvents = forwardEventsUtils(emits, pageEventsName, 'page-')
// 暴露table所有方法,可以在封装的组件中使用ref直接使用
const expose = exposeEventsUtils(tableRef, exposeEvents)
defineExpose({ ...expose })
const paginationClass = computed(() => {
let defaultsClass = 'justify-center'
if (props.pagination && props.pagination.align) {
if (props.pagination.align === 'left') {
defaultsClass = 'justify-start'
}
if (props.pagination.align === 'right') {
defaultsClass = 'justify-end'
}
}
return defaultsClass
})
// 设置table-columns默认的属性值
const columnDefaults = {
sortable: false,
'sort-orders': ['ascending', 'descending', null],
resizable: true,
align: 'left',
'reserve-selection': false,
'filter-multiple': true
}
// 默认值的属性添加到table-column上
function setColumnDefault(column: TableColumnCtx) {
return { ...columnDefaults, ...column }
}
</script>
5.工具函数 format.ts
typescript
import type { Ref } from 'vue'
/**
* 将kebab-case(短横线命名法)转换为camelCase(驼峰命名法)
* @param str 需要转换的字符串,格式为kebab-case(如:hello-world)
* @returns 转换后的camelCase格式字符串(如:helloWorld)
*/
export function kebabToCamel(str: string): string {
// 使用正则表达式匹配所有短横线后跟小写字母的情况
// 替换函数将匹配到的字母转换为大写
return str.replace(/-([a-z])/g, function (g) {
// g是匹配到的结果,g[1]是短横线后的第一个小写字母
// 将该字母转换为大写并返回
return g[1].toUpperCase()
})
}
// 设置一个转换函数,将所有事件函数放在一个对象中,用v-on="对象"绑定到el-table上
export const forwardEventsUtils = (emits: any, array: string[], prefix: string = '') => {
// 创建一个对象,用于存储所有事件函数。Record用于创建一个对象类型,其键和值都有指定的类型
const forwardEvents: Record<string, (...args: any[]) => void> = {}
array.forEach((eventName) => {
// 将item从camel-case转换为camelCase
const name = kebabToCamel(eventName)
// (...args: any[]) => {}:定义一个接收任意参数的箭头函数
forwardEvents[name] = (...args: any[]) => {
// 触发对应的事件,并传递所有, 分页事件须加prefix前缀page-
emits(prefix + eventName, ...args)
}
})
return forwardEvents
}
// 如上,再将table中的方法函数放在一个对象中,用expose(对象)供封装的组件使用
export const exposeEventsUtils = (ref: Ref<any>, array: string[]) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
const exposeMethods: Record<string, Function> = {}
array.forEach((exposeName) => {
// 例如:obj= {clearSelection:(...args)=> tabelRef.value.clearSelection(...args)}
exposeMethods[exposeName] = (...args: any[]) => {
if (ref.value && typeof ref.value[exposeName] === 'function') {
return ref.value[exposeName](...args)
}
}
})
return exposeMethods
}
6.基础表格demo,index.vue
xml
<template>
<div class="m-4">
<p>基础表格示例</p>
<el-tabs v-model="activeName" class="demo-tabs">
<el-tab-pane label="基础表格" name="first">
<VTable :columns="columns" :data="tableData" :pagination="pagination" @page-current-change="handleCurrentChange" @page-size-change="handleCurrentChange"
@page-next-change="handleCurrentChange"
@page-prev-change="handleCurrentChange"
/>
</el-tab-pane>
<el-tab-pane label="插槽封装表格" name="second">
<VTable :columns="columns" :data="tableData">
<template #append> 我是append最后一行 </template>
</VTable>
</el-tab-pane>
<el-tab-pane label="scheme配置表格" name="third">
<VTable :columns="columns" :data="tableData">
<!-- 可以使用el-table的默认插槽展示自定义内容,也可通过下边scheme配置自定义内容 -->
<!-- <el-table-column fixed="right" label="Operations" min-width="120"> -->
<!-- <template #default="scope"> -->
<!-- <el-button link type="primary" size="small" @click="handleClick(scope.row)"> -->
<!-- Detail -->
<!-- </el-button> -->
<!-- <el-button link type="primary" size="small">Edit</el-button> -->
<!-- </template> -->
<!-- </el-table-column> -->
</VTable>
</el-tab-pane>
<el-tab-pane label="固定表头" name="fourth">
<VTable :columns="columns" :data="tableData" :height="200"></VTable>
</el-tab-pane>
<el-tab-pane label="流体高度" name="23">
<VTable :columns="columns" :data="tableData" :max-height="300"></VTable>
</el-tab-pane>
<el-tab-pane label="多级表头" name="233">
<VTable :data="tableData1" style="width: 100%" :columns="columns1">
<!-- <el-table-column prop="date" label="Date" width="150" /> -->
<!-- <el-table-column label="Delivery Info"> -->
<!-- <el-table-column prop="name" label="Name" width="120" /> -->
<!-- <el-table-column label="Address Info"> -->
<!-- <el-table-column prop="state" label="State" width="120" /> -->
<!-- <el-table-column prop="city" label="City" width="120" /> -->
<!-- <el-table-column prop="address" label="Address" /> -->
<!-- <el-table-column prop="zip" label="Zip" width="120" /> -->
<!-- </el-table-column> -->
<!-- </el-table-column> -->
</VTable>
</el-tab-pane>
<el-tab-pane label="事件封装表格" name="2332">
<VTable @row-click="handleRowClick" :columns="columns" :data="tableData"></VTable>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script setup lang="tsx">
import type { TableColumnType } from '@/components/Table/types'
definePage({
meta: {
title: 'pages.components.table-basic',
icon: 'meteor-icons:table-layout'
}
})
const pagination = ref({
align: 'right',
size: 'default',
small: false,
background: false,
layout: 'total, sizes, prev, pager, next, jumper',
pageSizes: [10, 20, 30, 40, 50, 100],
total: 100
})
const activeName = ref('first')
const tableData = [
{
date: '2016-05-03',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles'
},
{
date: '2016-05-02',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles'
},
{
date: '2016-05-04',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles'
},
{
date: '2016-05-01',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles'
},
{
date: '2016-04-01',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles'
},
{
date: '2016-05-08',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles'
},
{
date: '2016-05-09',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles'
},
{
date: '2016-05-10',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles'
}
]
const columns = [
{
prop: 'date',
label: '日期'
},
{
prop: 'name',
label: '姓名'
},
{
prop: 'address',
label: '地址'
},
{
prop: 'Operations',
label: '操作',
width: 120,
fixed: 'right',
defaultSlot: (_props) => (
<>
<el-button link type="primary" size="small" onClick={() => handleClick(_props)}>
detail
</el-button>
<el-button link type="primary" size="small">
Edit
</el-button>
</>
)
}
] as TableColumnType[]
const tableData1 = [
{
date: '2016-05-03',
name: 'Tom',
state: 'California',
city: 'Los Angeles',
address: 'No. 189, Grove St, Los Angeles',
zip: 'CA 90036'
},
{
date: '2016-05-02',
name: 'Tom',
state: 'California',
city: 'Los Angeles',
address: 'No. 189, Grove St, Los Angeles',
zip: 'CA 90036'
},
{
date: '2016-05-04',
name: 'Tom',
state: 'California',
city: 'Los Angeles',
address: 'No. 189, Grove St, Los Angeles',
zip: 'CA 90036'
},
{
date: '2016-05-01',
name: 'Tom',
state: 'California',
city: 'Los Angeles',
address: 'No. 189, Grove St, Los Angeles',
zip: 'CA 90036'
},
{
date: '2016-05-08',
name: 'Tom',
state: 'California',
city: 'Los Angeles',
address: 'No. 189, Grove St, Los Angeles',
zip: 'CA 90036'
},
{
date: '2016-05-06',
name: 'Tom',
state: 'California',
city: 'Los Angeles',
address: 'No. 189, Grove St, Los Angeles',
zip: 'CA 90036'
},
{
date: '2016-05-07',
name: 'Tom',
state: 'California',
city: 'Los Angeles',
address: 'No. 189, Grove St, Los Angeles',
zip: 'CA 90036'
}
]
const columns1 = [
{
prop: 'date',
label: 'Date',
width: 150
},
{
label: 'Delivery Info',
children: [
{
prop: 'name',
label: 'Name',
width: 120
},
{
label: 'Address Info',
children: [
{
prop: 'state',
label: 'State',
width: 120
},
{
prop: 'city',
label: 'City',
width: 120
},
{
prop: 'address',
label: 'Address'
},
{
prop: 'zip',
label: 'Zip',
width: 120
}
]
}
]
}
]
const handleClick = (row) => {
console.log('🚀 ~ handleClick ~ row:', row)
}
const handleRowClick = (...args) => {
console.log('🚀 ~ handleRowClick ~ args:', args)
}
const handleCurrentChange = (val) => {
console.log('🚀 ~ handleCurrentChange ~ val:', val)
}
</script>
<style scoped></style>
复杂列表格complex-table.vue
typescript
<template>
<div class="m-4">
<p>复杂列表格示例</p>
<el-tabs v-model="activeName" class="demo-tabs">
<el-tab-pane label="单选表格" name="first">
<VTable
@row-click="handleRowClick"
highlight-current-row
:columns="columns"
:data="tableData"
></VTable>
<div class="mt-4 w-full">所选表格项:{{ singleSelection }}</div>
</el-tab-pane>
<el-tab-pane label="多选表格" name="second">
<VTable
ref="multipleTableRef"
:columns="columns1"
:data="tableData1"
row-key="id"
@selection-change="handleSelectionChange"
>
</VTable>
<div class="mt-4 w-full">
<el-button @click="toggleSelection([tableData1[1], tableData1[2]])">
切换第二行和第三行的选中状态
</el-button>
<el-button @click="toggleSelection([tableData1[1], tableData1[2]], false)">
根据可选状态切换选择状态
</el-button>
<el-button @click="toggleSelection()">清除选中项</el-button>
</div>
</el-tab-pane>
<el-tab-pane label="排序表格" name="3">
<VTable
:columns="columns1"
:data="tableData1"
:default-sort="{ prop: 'date', order: 'descending' }"
></VTable>
</el-tab-pane>
<el-tab-pane label="筛选表格" name="4">
<VTable
ref="filterTableRef"
:columns="columnsFilter"
:data="tableDataFilter"
row-key="date"
></VTable>
<div>
<el-button @click="resetDateFilter">重置 date 筛选</el-button>
<el-button @click="clearFilter">重置所有筛选 </el-button>
</div>
</el-tab-pane>
<el-tab-pane label="树型表格" name="5">
<VTable
:columns="columnsTree"
:data="tableDataTree"
row-key="id"
border
default-expand-all
></VTable>
</el-tab-pane>
<el-tab-pane label="表尾合计行" name="6">
<VTable
:columns="sumColumns"
:data="sumTableData"
border
height="200"
:summary-method="getSummaries"
show-summary
></VTable>
</el-tab-pane>
<el-tab-pane label="合并行或列" name="7">
<VTable
:columns="sumColumns"
:data="sumTableData1"
border
:span-method="arraySpanMethod"
></VTable>
<VTable
class="mt-10"
:columns="sumColumns"
:data="sumTableData1"
border
:span-method="objectSpanMethod"
></VTable>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script setup lang="tsx">
import type { TableColumnType } from '@/components/Table/types'
definePage({
meta: {
title: '复杂列表格',
icon: 'mdi:grid'
}
})
const activeName = ref('first')
// ------------------单选------------------
const tableData = [
{
date: '2016-05-03',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles'
},
{
date: '2016-05-02',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles'
},
{
date: '2016-05-04',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles'
},
{
date: '2016-05-01',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles'
},
{
date: '2016-04-01',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles'
},
{
date: '2016-05-08',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles'
},
{
date: '2016-05-09',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles'
},
{
date: '2016-05-10',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles'
}
]
const columns = [
{
prop: 'date',
label: '日期'
},
{
prop: 'name',
label: '姓名'
},
{
prop: 'address',
label: '地址'
},
{
prop: 'Operations',
label: '操作',
width: 120,
fixed: 'right',
defaultSlot: (_props) => (
<>
<el-button
link
type="primary"
size="small"
onClick={(e) => {
e.stopPropagation()
handleClick(_props.row, 'detail')
}}
>
detail
</el-button>
<el-button
link
type="primary"
size="small"
onClick={(e) => {
e.stopPropagation()
handleClick(_props.row, 'edit')
}}
>
Edit
</el-button>
</>
)
}
] as TableColumnType[]
const singleSelection = ref<any[]>()
const handleClick = (row, type: string) => {
console.log('🚀 ~ handleClick ~ row:', row)
}
const handleRowClick = (...args) => {
console.log('🚀 ~ handleRowClick ~ args:', args)
singleSelection.value = args
}
// --------------------多选--------------------
import type { TableColumnCtx, TableInstance } from 'element-plus'
interface User {
id?: number | string
date: string
name: string
address: string
tag?: string
children?: User[]
}
const multipleTableRef = ref<TableInstance>()
const multipleSelection = ref<User[]>([])
const toggleSelection = (rows?: User[], ignoreSelectable?: boolean) => {
if (rows) {
rows.forEach((row) => {
multipleTableRef.value!.toggleRowSelection(row, undefined, ignoreSelectable)
})
} else {
multipleTableRef.value!.clearSelection()
}
}
const handleSelectionChange = (val: User[]) => {
multipleSelection.value = val
}
const columns1 = [
{
type: 'selection',
width: 55,
selectable: (row: User) => ![1, 2].includes(row.id! as number)
},
{
prop: 'date',
sortable: true,
label: '日期'
},
{
prop: 'name',
label: '姓名'
},
{
prop: 'address',
label: '地址'
},
{
prop: 'Operations',
label: '操作',
width: 120,
fixed: 'right',
defaultSlot: (_props) => (
<>
<el-button
link
type="primary"
size="small"
onClick={(e) => {
e.stopPropagation()
handleClick(_props.row, 'detail')
}}
>
detail
</el-button>
<el-button
link
type="primary"
size="small"
onClick={(e) => {
e.stopPropagation()
handleClick(_props.row, 'edit')
}}
>
Edit
</el-button>
</>
)
}
]
const tableData1: User[] = [
{
id: 1,
date: '2016-05-03',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles'
},
{
id: 2,
date: '2016-05-02',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles'
},
{
id: 3,
date: '2016-05-04',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles'
},
{
id: 4,
date: '2016-05-01',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles'
},
{
id: 5,
date: '2016-05-08',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles'
},
{
id: 6,
date: '2016-05-06',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles'
},
{
id: 7,
date: '2016-05-07',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles'
}
]
// ----------------筛选----------------
const columnsFilter = [
{
prop: 'date',
label: '日期',
columnKey: 'date',
filters: [
{ text: '2016-05-01', value: '2016-05-01' },
{ text: '2016-05-02', value: '2016-05-02' },
{ text: '2016-05-03', value: '2016-05-03' },
{ text: '2016-05-04', value: '2016-05-04' }
],
filterMethod: (value: string, row: User, column: TableColumnCtx<User>) => {
const property = column['property']
return row[property] === value
}
},
{
prop: 'name',
label: '姓名'
},
{
prop: 'address',
label: '地址'
},
{
prop: 'tag',
label: 'Tag',
filters: [
{ text: 'Home', value: 'Home' },
{ text: 'Office', value: 'Office' }
],
filterMethod: (value: string, row: User) => row.tag === value
}
]
const tableDataFilter: User[] = [
{
date: '2016-05-03',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
tag: 'Home'
},
{
date: '2016-05-02',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
tag: 'Office'
},
{
date: '2016-05-04',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
tag: 'Home'
},
{
date: '2016-05-01',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
tag: 'Office'
}
]
const filterTableRef = ref<TableInstance>()
const resetDateFilter = () => {
filterTableRef.value!.clearFilter(['date'])
}
const clearFilter = () => {
filterTableRef.value!.clearFilter()
}
// -------------树型表格----------------
const tableDataTree: User[] = [
{
id: 1,
date: '2016-05-02',
name: 'wangxiaohu',
address: 'No. 189, Grove St, Los Angeles'
},
{
id: 2,
date: '2016-05-04',
name: 'wangxiaohu',
address: 'No. 189, Grove St, Los Angeles'
},
{
id: 3,
date: '2016-05-01',
name: 'wangxiaohu',
address: 'No. 189, Grove St, Los Angeles',
children: [
{
id: 31,
date: '2016-05-01',
name: 'wangxiaohu',
address: 'No. 189, Grove St, Los Angeles'
},
{
id: 32,
date: '2016-05-01',
name: 'wangxiaohu',
address: 'No. 189, Grove St, Los Angeles'
}
]
},
{
id: 4,
date: '2016-05-03',
name: 'wangxiaohu',
address: 'No. 189, Grove St, Los Angeles'
}
]
const columnsTree = [
{
prop: 'date',
label: '日期'
},
{
prop: 'name',
label: '姓名'
},
{
prop: 'address',
label: '地址'
}
]
// ------------------表尾合计行-----------------
interface Product {
id: string
name: string
amount1: string
amount2: string
amount3: number
}
const sumColumns = [
{
prop: 'id',
label: 'id'
},
{
prop: 'name',
label: '姓名'
},
{
prop: 'amount1',
label: 'amount1'
},
{
prop: 'amount2',
label: 'amount2'
},
{
prop: 'amount3',
label: 'amount3'
}
]
const sumTableData: Product[] = [
{
id: '12987122',
name: 'Tom',
amount1: '234',
amount2: '3.2',
amount3: 10
},
{
id: '12987123',
name: 'Tom',
amount1: '165',
amount2: '4.43',
amount3: 12
},
{
id: '12987124',
name: 'Tom',
amount1: '324',
amount2: '1.9',
amount3: 9
},
{
id: '12987125',
name: 'Tom',
amount1: '621',
amount2: '2.2',
amount3: 17
},
{
id: '12987126',
name: 'Tom',
amount1: '539',
amount2: '4.1',
amount3: 15
}
]
interface SummaryMethodProps<T = Product> {
columns: TableColumnType[]
data: T[]
}
const getSummaries = (param: SummaryMethodProps) => {
const { columns, data } = param
const sums: (string | VNode)[] = []
columns.forEach((column, index) => {
if (index === 0) {
sums[index] = h('div', { style: { textDecoration: 'underline' } }, ['Total Cost'])
return
}
const values = data.map((item) => Number(item[column.property]))
if (!values.every((value) => Number.isNaN(value))) {
sums[index] = `$ ${values.reduce((prev, curr) => {
const value = Number(curr)
if (!Number.isNaN(value)) {
return prev + curr
} else {
return prev
}
}, 0)}`
} else {
sums[index] = 'N/A'
}
})
return sums
}
// -------------合并行或列-----------------
interface SpanMethodProps {
row: User
column: TableColumnCtx<User>
rowIndex: number
columnIndex: number
}
const arraySpanMethod = ({ row, column, rowIndex, columnIndex }: SpanMethodProps) => {
if (rowIndex % 2 === 0) {
if (columnIndex === 0) {
return [1, 2]
} else if (columnIndex === 1) {
return [0, 0]
}
}
}
const objectSpanMethod = ({ row, column, rowIndex, columnIndex }: SpanMethodProps) => {
if (columnIndex === 0) {
if (rowIndex % 2 === 0) {
return {
rowspan: 2,
colspan: 1
}
} else {
return {
rowspan: 0,
colspan: 0
}
}
}
}
const sumTableData1: Product[] = [
{
id: '12987122',
name: 'Tom',
amount1: '234',
amount2: '3.2',
amount3: 10
},
{
id: '12987123',
name: 'Tom',
amount1: '165',
amount2: '4.43',
amount3: 12
},
{
id: '12987124',
name: 'Tom',
amount1: '324',
amount2: '1.9',
amount3: 9
},
{
id: '12987125',
name: 'Tom',
amount1: '621',
amount2: '2.2',
amount3: 17
},
{
id: '12987126',
name: 'Tom',
amount1: '539',
amount2: '4.1',
amount3: 15
}
]
</script>
<style scoped></style>