为什么写这个
- 官网没有直接的示例来说明如何自适应父容器大小
- 网上其他博客上的实现方式过于复杂(需要计算表头高度,计算容器高度,计算其他元素高度,再
将容器高度-表头高度-其他元素高度,以此得到最终的表格体高度)
自适应父容器大小是什么意思?
表格占满父容器的宽高,如果父容器的宽高不足以容纳所有数据,则出现滚动条。
实现效果
数据少的情况
数据多的情况
存在冻结列的情况
存在表头分组和冻结列的情况
已知的适用版本
ant design vue 4.x
实现思路
该方案特点: 无论是否启用分页,都适用
- 通过css样式,让表格高度为100%(占满父容器)
此时要求父容器必须有高度 - 让表格成为一个flex容器,flex的方向为column, 表头设置为
flex-shrink: 0,表体设置为flex:1;height:0; - 如果是分页表格,则还需要将表格的父容器设置为flex容器,flex的方向为column,将分页组件所在的dom设置为
flex-shrink: 0,再将表格设置为flex:1;height:0; - a-table的x,y都设置为
max-content,scroll="{ x: 'max-content', y: 'max-content' }" - 如果
max-content设置存在问题,可以换成100%试试
具体代码
<template>
<!-- vp-raw的作用是隔绝vitepress样式对当前组件的样式影响 -->
<div class="vp-raw" style="height: 560px">
<div class="custom-antd-table-wrapper">
<a-table
:columns="columns"
:data-source="data"
:scroll="{ x: 'max-content', y: 'max-content',hideOnSinglePage:true }"
>
<!-- 自定义表头 -->
<template #headerCell="{ column }">
<template v-if="column.key === 'name'">
<span>
<smile-outlined />
{{ column.title }}
</span>
</template>
</template>
<!-- 自定义单元格 -->
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'name'">
<a>
{{ record.name }}
</a>
</template>
<template v-else-if="column.key === 'tags'">
<span>
<a-tag
v-for="tag in record.tags"
:key="tag"
:color="tag === 'loser' ? 'volcano' : tag.length > 5 ? 'geekblue' : 'green'"
>
{{ tag.toUpperCase() }}
</a-tag>
</span>
</template>
<template v-else-if="column.key === 'action'">
<span>
<a>Invite 一 {{ record.name }}</a>
<a-divider type="vertical" />
<a>Delete</a>
<a-divider type="vertical" />
<a class="ant-dropdown-link">
More actions
<down-outlined />
</a>
</span>
</template>
</template>
</a-table>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, computed } from 'vue'
import { SmileOutlined, DownOutlined } from '@ant-design/icons-vue'
import type { TableColumnType } from 'ant-design-vue'
interface UserInfo {
key: string
name: string
age: number
address: string
tags: string[]
}
const columns: TableColumnType<UserInfo>[] = [
{
title: '姓名',
dataIndex: 'name',
width: 200,
key: 'name',
customCell: () => {
return {
style: {
color: 'red',
},
onClick: event => {
alert(123)
},
}
},
},
{
title: '年龄',
dataIndex: 'age',
width: 200,
key: 'age',
},
{
title: '地址',
dataIndex: 'address',
key: 'address',
width: 100,
ellipsis: true,
},
{
title: '标签',
dataIndex: 'tags',
key: 'tags',
width: 200,
},
{
title: '动作',
key: 'action',
width: 200,
},
]
const data: UserInfo[] = [
{
key: '1',
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park',
tags: ['nice', 'developer'],
},
{
key: '2',
name: 'Jim Green',
age: 42,
address: 'London No. 1 Lake Park',
tags: ['loser'],
},
{
key: '3',
name: 'Joe Black',
age: 32,
address: 'Sidney No. 1 Lake Park',
tags: ['cool', 'teacher'],
},
]
</script>
<style scoped lang="less">
.custom-antd-table-wrapper {
height: 100%;
::v-deep(.ant-table-wrapper) {
height: 100%;
.ant-spin-nested-loading {
height: 100%;
}
.ant-spin-container {
height: 100%;
display: flex;
flex-direction: column;
.ant-table {
flex: 1;
height: 0;
}
.ant-pagination {
flex-shrink: 0;
}
}
.ant-table-container {
height: 100%;
display: flex;
flex-direction: column;
> .ant-table-header {
flex-shrink: 0;
}
> .ant-table-body {
flex: 1;
height: 0;
}
}
}
}
</style>
其他补充问题
- 自适应父容器大小,如果父容器是模态框之类的弹窗,如果这个弹窗的显示存在动效(比如:从小逐渐增大),那会影响a-table计算父容器的大小。解决方案:要么去除动效,要么等动效执行完毕之后,再渲染a-table