Ant Design Vue 4-表格(Table)

前言

https://www.antdv.com/components/overview-cn/

https://www.antdv.com/components/table-cn

基本实例

1
<a-table :dataSource="dataSource" :columns="columns" :pagination="false"/>

TS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
const columns = reactive([
{
title: '姓名',
dataIndex: 'name',
key: 'name',
},
{
title: '年龄',
dataIndex: 'age',
key: 'age',
},
{
title: '住址',
dataIndex: 'address',
key: 'address',
},
])

const dataSource = reactive([
{
key: '1',
name: '胡彦斌',
age: 32,
address: '西湖区湖底公园1号',
},
{
key: '2',
name: '胡彦祖',
age: 42,
address: '西湖区湖底公园1号',
}
])

表格+分页

1
2
3
4
5
6
7
8
9
10
11
<a-table :dataSource="dataSource" :columns="columns" :pagination="false" :scroll="{ x: 'max-content' }"/>
<a-flex justify="flex-end">
<a-pagination
v-model:current="currentPage"
:total="totalNum"
@change="pageChange"
:showSizeChanger="false"
:show-total="(total: any) => `共 ${total} 条`"
class="z_margin_t_l"
/>
</a-flex>

其中

:showSizeChanger="false":不展示 pageSize 切换器。

TS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
const columns = reactive([
{
title: '姓名',
dataIndex: 'name',
key: 'name'
},
{
title: '年龄',
dataIndex: 'age',
key: 'age'
},
{
title: '住址',
dataIndex: 'address',
key: 'address'
}
])

const dataSource = reactive([
{
key: '1',
name: '胡彦斌',
age: 32,
address: '西湖区湖底公园1号'
},
{
key: '2',
name: '胡彦祖',
age: 42,
address: '西湖区湖底公园1号'
}
])


//当前页码 从1开始
const currentPage = ref(1)
//数据总条数
const totalNum = ref(30)
function pageChange(page: number, pageSize: number) {
console.info('page', page)
console.info('pageSize', pageSize)
}

模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<a-table :dataSource="dataSource" :columns="columns" :pagination="false">
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'noticeStatus'">
<a-tag :bordered="false" color="success" v-show="record.noticeStatus === 1">已读</a-tag>
<a-tag :bordered="false" color="warning" v-show="record.noticeStatus === 0">未读</a-tag>
</template>

<template v-if="column.key === 'noticeTitle'">
<a-space direction="vertical" :size="0">
<div class="z_text_m">{{ record.noticeTitle }}</div>
<div class="z_text_tip">{{ record.noticeInfo }}</div>
</a-space>
</template>
</template>
</a-table>

TS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
const columns = reactive([
{
title: '消息状态',
key: 'noticeStatus'
},
{
title: '类型',
dataIndex: 'noticeTypeName'
},
{
title: '标题',
key: 'noticeTitle'
},
{
title: '创建时间',
dataIndex: 'createtime'
}
])

const dataSource = reactive([
{
noticeStatus: 1,
noticeTypeName: '平台通知',
noticeTitle: '周末活动-招商-数量有限先到先得',
noticeInfo:
'活动时间:7月31号~8月1号(周末两天)报名时间:7月27号产品活动在线时间:最高2天 规则要求',
createtime: '2024-06-22 15:40:59'
}
])

操作按钮

1
2
3
4
5
6
7
8
9
10
11
12
<a-table :dataSource="dataSource" :columns="columns" :pagination="false">
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'operation'">
<a-space :size="0">
<a-button type="link" size="small">编辑</a-button>
<a-popconfirm title="确定要删除吗?" ok-text="是" cancel-text="否" @confirm="delItemClick(record)">
<a-button type="link" danger size="small">删除</a-button>
</a-popconfirm>
</a-space>
</template>
</template>
</a-table>

TS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
const columns = reactive([
{
title: '热词',
dataIndex: 'name',
key: 'name'
},
{
title: '热度',
dataIndex: 'hotNum',
key: 'hotNum'
},
{
title: '添加人',
dataIndex: 'createName',
key: 'address'
},
{
title: '添加时间',
align: 'center',
dataIndex: 'createtime',
key: 'createtime'
},
{
title: '操作',
width: 160,
align: 'center',
fixed: 'right',
key: 'operation'
}
])

const dataSource = reactive([
{
key: '1',
name: 'iphone8',
hotNum: 100,
createName: '张三',
createtime: '2024-10-10 16:30:30'
},
{
key: '2',
name: '华为',
hotNum: 42,
createName: '李四',
createtime: '2024-10-10 16:30:30'
}
])

水平滚动条

1
<a-table :dataSource="dataSource" :columns="columns" :scroll="{ x: 'max-content' }"> </a-table>

x: 'max-content'指的是水平超过max-content就会产生滚动条

固定的区域使用fixed实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const columns = reactive([
{
title: '商品编号',
dataIndex: 'name',
width: 140
},
{
title: '商品名称',
dataIndex: 'goodsname',
width: 400
},
{
title: '操作',
width: 160,
align: 'center',
fixed: 'right',
key: 'operation'
}
])

树状表格

只要表格的数据是树状数据即可

1
2
3
4
5
6
7
8
<a-table
:dataSource="dataList"
:columns="columns"
rowKey="menuid"
:pagination="false"
childrenColumnName="childList"
>
</a-table>

其中

childrenColumnName是子列表的字段。

rowKey是行的唯一标识,如果不设置会出现一展开全都展开的情况。

跨页多选

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
<template>
<div class="SelectCustomerView">
<a-card>
<a-flex gap="small" wrap="wrap">
已选择用户:
<a-tag
:bordered="false"
color="orange"
closable
v-for="(item, index) in allSelectList"
:key="index"
@close.prevent="closeTag(item, index)"
>{{ item.name }}
</a-tag>
</a-flex></a-card
>
<a-card class="z_margin_t_l">
<a-space size="middle" :wrap="true" style="width: 100%">
<a-space align="center">
<span>关键字:</span>
<a-input v-model:value="filterObj.name" placeholder="请输入用户名" />
</a-space>

<a-space size="middle">
<a-button type="primary" @click="actionList">搜索</a-button>
<a-button @click="resetClick">重置</a-button>
</a-space>
</a-space>
<div class="z_line_h"></div>

<div class="z_margin_t_m"></div>
<a-table
:row-selection="rowSelection"
:row-key="rowKey"
:dataSource="dataList"
:columns="columns"
:pagination="false"
>
</a-table>

<a-flex justify="flex-end">
<a-pagination v-model:current="currentPage" :total="totalNum" class="z_margin_t_l" />
</a-flex>
</a-card>
</div>
</template>

<script lang="ts" setup>
import { onMounted, reactive, ref, watch } from 'vue'
import { apiCustomerList } from '@/assets/api/customer_api'
import type { TableProps } from 'ant-design-vue'

const model = defineModel<TCustomer[]>()

const filterObj = reactive({
name: ''
})

function resetClick() {
filterObj.name = ''
actionList()
}

const columns = reactive([
{
title: '姓名',
dataIndex: 'name'
},
{
title: '手机号',
dataIndex: 'phone'
}
])
const dataList: TCustomer[] = reactive([])

const allSelectList: TCustomer[] = reactive([])
const mSelectedRowKeys: number[] = reactive([])
const rowKey = (record: TCustomer) => record.customerid
const rowSelection: TableProps['rowSelection'] = {
selectedRowKeys: mSelectedRowKeys,
onChange: (selectedRowKeys: any[], selectedRows: TCustomer[]) => {
mSelectedRowKeys.length = 0
mSelectedRowKeys.push(...selectedRowKeys)
//先移除本页之前有的值
let allArr = model.value || []
allArr = allArr.filter((item) => {
const currIdArr = dataList.map((dItem) => dItem.customerid)
return !currIdArr.includes(item.customerid)
})
//再添加本页选中的值
allArr.push(...selectedRows)
allSelectList.length = 0
allSelectList.push(...allArr)
model.value = allSelectList
}
}

function closeTag(item: TCustomer, index: number) {
allSelectList.splice(index, 1)
let keyIndex = mSelectedRowKeys.indexOf(item.customerid)
if (keyIndex != -1) {
mSelectedRowKeys.splice(keyIndex, 1)
}

model.value = allSelectList
}

//当前页码 从1开始
const currentPage = ref(1)
//数据总条数
const totalNum = ref(0)

watch(currentPage, async () => {
await actionList()
let allArr = model.value || []
let tempArr = allArr.filter((item) => {
const currArr = dataList.map((dItem) => dItem.customerid)
return currArr.includes(item.customerid)
})
mSelectedRowKeys.length = 0

let allIdArr = tempArr.map((item) => item.customerid)
mSelectedRowKeys.push(...allIdArr)
})

onMounted(() => {
actionList()
})

async function actionList() {
let page = currentPage.value
let size = 10
let { name } = filterObj
let result = await apiCustomerList(page, size, name)
dataList.length = 0
if (result.code == 0) {
dataList.push(...result.obj)
totalNum.value = result.total
}
}
</script>

<style src="./SelectCustomerView.less" lang="less" scoped></style>

表格单选

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
<template>
<div class="SelectGoodsSingleView">
<a-card>
<a-flex gap="small" wrap="wrap">
已选择商品:
<a-tag :bordered="false" color="orange" v-if="model" closable @close.prevent="closeTag()">
{{ model.name }}
</a-tag>
</a-flex></a-card
>
<a-card class="z_margin_t_l">
<a-space size="middle" :wrap="true" style="width: 100%">
<a-space align="center">
<span>关键字:</span>
<a-input v-model:value="filterObj.name" placeholder="请输入用户名" />
</a-space>

<a-space size="middle">
<a-button type="primary" @click="actionList">搜索</a-button>
<a-button @click="resetClick">重置</a-button>
</a-space>
</a-space>
<div class="z_line_h"></div>

<div class="z_margin_t_m"></div>
<a-table
:row-selection="rowSelection"
:row-key="rowKey"
:dataSource="dataList"
:columns="columns"
:pagination="false"
>
</a-table>

<a-flex justify="flex-end">
<a-pagination v-model:current="currentPage" :total="totalNum" class="z_margin_t_l" />
</a-flex>
</a-card>
</div>
</template>

<script lang="ts" setup>
import { onMounted, reactive, ref } from 'vue'
import type { TableProps } from 'ant-design-vue'
import { apiGoodsListSel } from '@/assets/api/goods_api'

const model = defineModel<TGoods | null>()

const filterObj = reactive({
name: ''
})

function resetClick() {
filterObj.name = ''
actionList()
}

const columns = reactive([
{
title: '姓名',
dataIndex: 'name'
},
{
title: '商品编码',
dataIndex: 'goodsCode'
},
{
title: '店铺名称',
dataIndex: 'storename'
}
])
const dataList: TGoods[] = reactive([])
const mSelectedRowKeys: number[] = reactive([])
const rowKey = (record: TGoods) => record.goodsId
const rowSelection: TableProps['rowSelection'] = {
selectedRowKeys: mSelectedRowKeys,
onChange: (selectedRowKeys: any[], selectedRows: TGoods[]) => {
mSelectedRowKeys.length = 0
mSelectedRowKeys.push(selectedRowKeys[selectedRowKeys.length - 1])

model.value = selectedRows[selectedRows.length - 1]
}
}

function closeTag() {
mSelectedRowKeys.length = 0
model.value = null
}

//当前页码 从1开始
const currentPage = ref(1)
//数据总条数
const totalNum = ref(0)

onMounted(() => {
actionList()
})

async function actionList() {
let page = currentPage.value
let size = 10
let { name } = filterObj
let result = await apiGoodsListSel(page, size, name)
dataList.length = 0
if (result.code == 0) {
dataList.push(...result.obj)
totalNum.value = result.total
}
}
</script>

<style src="./SelectGoodsSingleView.less" lang="less" scoped></style>