Vue+Ant Design開發(fā)簡單表格組件的實戰(zhàn)指南
前言
在現(xiàn)代前端開發(fā)中,數(shù)據(jù)表格是展示信息最常用的組件之一。本文將詳細記錄一個基于Vue和Ant Design的表格組件開發(fā)過程,從最初的需求實現(xiàn)到遇到問題,再到最終優(yōu)化方案的完整思考過程。通過這個實際案例,我們將探討如何構(gòu)建一個高效、用戶友好的數(shù)據(jù)表格組件,特別是處理固定列和滾動區(qū)域的復(fù)雜交互。
一、項目背景與需求分析
我們的項目需要開發(fā)一個媒體廣告抓取記錄查看功能,主要需求包括:
- 展示媒體廣告位的抓取記錄數(shù)據(jù)
- 支持分頁和排序功能
- 關(guān)鍵信息需要固定顯示(左右兩側(cè))
- 中間區(qū)域可橫向滾動查看更多數(shù)據(jù)字段
- 良好的性能表現(xiàn),支持大數(shù)據(jù)量
基于這些需求,我們選擇了Ant Design Vue作為UI組件庫,其強大的Table組件非常適合這類需求。
二、基礎(chǔ)實現(xiàn)
2.1 組件結(jié)構(gòu)設(shè)計
首先我們創(chuàng)建了GraspingRecordModal.vue組件,基礎(chǔ)結(jié)構(gòu)如下:
<template>
<a-modal
title="抓取記錄"
:visible="visible"
width="90%"
:footer="null"
@cancel="handleCancel"
>
<a-table
rowKey="id"
:columns="columns"
:dataSource="data"
:pagination="pagination"
:loading="loading"
@change="handleTableChange"
>
<!-- 自定義渲染插槽 -->
</a-table>
</a-modal>
</template>
2.2 數(shù)據(jù)獲取與處理
數(shù)據(jù)獲取使用異步請求,處理函數(shù)如下:
async fetchData() {
this.loading = true;
try {
const { data: res } = await getGraspingRecords({
mediaAdId: this.mediaAdId,
page: this.pagination.current,
pageSize: this.pagination.pageSize
});
if (res.code === '000000') {
this.data = res.data.aaData || [];
this.pagination.total = res.data.iTotalRecords || 0;
} else {
throw new Error(res.msg || '獲取數(shù)據(jù)失敗');
}
} catch (error) {
console.error('獲取抓取記錄失敗:', error);
this.$message.error(error.message);
} finally {
this.loading = false;
}
}
2.3 初始列配置
最初的列配置嘗試固定左右兩側(cè)的關(guān)鍵信息:
columns: [
{
title: '任務(wù)ID',
dataIndex: 'graspingTaskId',
width: 180,
fixed: 'left'
},
// ...其他中間列...
{
title: '狀態(tài)',
dataIndex: 'graspingStatus',
scopedSlots: { customRender: 'graspingStatus' },
width: 100,
fixed: 'right'
}
]
三、遇到的問題與初步解決方案
3.1 空白表格區(qū)域問題
在初步實現(xiàn)中,我們發(fā)現(xiàn)表格左右兩側(cè)出現(xiàn)了不必要的空白區(qū)域,這嚴重影響了用戶體驗和視覺效果。
問題表現(xiàn):
- 固定列與非固定列之間存在間隙
- 滾動區(qū)域兩側(cè)出現(xiàn)空白
- 表格整體布局不緊湊
3.2 原因分析
經(jīng)過調(diào)試,我們發(fā)現(xiàn)了幾個關(guān)鍵問題:
- 寬度計算不準(zhǔn)確:固定列和非固定列的寬度總和與表格容器寬度不匹配
- 滾動設(shè)置不當(dāng):
scroll.x值設(shè)置不合理 - CSS樣式?jīng)_突:Ant Design默認樣式與我們的需求有沖突
3.3 初步修復(fù)嘗試
我們首先嘗試調(diào)整列寬和滾動設(shè)置:
:scroll="{ x: 1800 }" // 根據(jù)列寬總和設(shè)置固定值
同時調(diào)整了一些列的寬度:
{
title: '任務(wù)ID',
dataIndex: 'graspingTaskId',
width: 150, // 縮小寬度
fixed: 'left',
ellipsis: true // 添加省略號
}
四、深度優(yōu)化方案
4.1 完美的解決方案
經(jīng)過多次嘗試,我們找到了最合適的配置方案:
<a-table
:scroll="{ x: 'max-content' }"
:columns="columns"
bordered
size="middle"
>
配合以下CSS修正:
.grasping-record-modal >>> .ant-table {
min-width: 100%;
}
.grasping-record-modal >>> .ant-table-container {
overflow-x: auto !important;
}
.grasping-record-modal >>> .ant-table-body {
overflow-x: auto !important;
}
4.2 優(yōu)化后的列配置
columns: [
{
title: '任務(wù)ID',
dataIndex: 'graspingTaskId',
width: 180,
fixed: 'left',
ellipsis: true
},
{
title: '總?cè)罩緮?shù)',
dataIndex: 'totalCount',
width: 100,
fixed: 'left',
align: 'center'
},
// 中間可滾動列...
{
title: '狀態(tài)',
dataIndex: 'graspingStatus',
scopedSlots: { customRender: 'graspingStatus' },
width: 100,
fixed: 'right',
align: 'center'
},
{
title: '抓取時間',
dataIndex: 'graspingTime',
scopedSlots: { customRender: 'time' },
width: 180,
fixed: 'right'
}
]
4.3 關(guān)鍵優(yōu)化點
- 使用’max-content’:讓表格根據(jù)內(nèi)容自動計算寬度
- 強制溢出設(shè)置:確保滾動行為符合預(yù)期
- 最小寬度保證:防止容器意外收縮
- 列對齊統(tǒng)一:所有數(shù)值列居中對齊
- 固定列優(yōu)化:左右兩側(cè)固定列寬度適當(dāng)加大
五、完整優(yōu)化代碼
以下是經(jīng)過全面優(yōu)化后的完整組件代碼:
<template>
<a-modal
title="抓取記錄"
:visible="visible"
width="90%"
:footer="null"
@cancel="handleCancel"
:destroyOnClose="true"
class="grasping-record-modal"
>
<a-table
rowKey="id"
:columns="columns"
:dataSource="data"
:pagination="pagination"
:loading="loading"
:scroll="{ x: 'max-content' }"
@change="handleTableChange"
bordered
size="middle"
>
<template slot="graspingStatus" slot-scope="text">
<a-tag :color="getStatusColor(text)">
{{ getStatusText(text) }}
</a-tag>
</template>
<template slot="time" slot-scope="text">
{{ formatDateTime(text) }}
</template>
</a-table>
</a-modal>
</template>
<script>
import dayjs from 'dayjs'
import { getGraspingRecords } from '@/api/ad-api/media'
export default {
name: 'GraspingRecordModal',
data() {
return {
loading: false,
data: [],
pagination: {
current: 1,
pageSize: 10,
total: 0,
showSizeChanger: true,
pageSizeOptions: ['10', '20', '50', '100'],
showTotal: total => `共 ${total} 條記錄`
},
columns: [
{
title: '任務(wù)ID',
dataIndex: 'graspingTaskId',
width: 180,
fixed: 'left',
ellipsis: true
},
{
title: '總?cè)罩緮?shù)',
dataIndex: 'totalCount',
width: 100,
fixed: 'left',
align: 'center'
},
{
title: '設(shè)備ID',
dataIndex: 'deviceIdCount',
width: 100,
align: 'center'
},
{
title: '啟動時間',
dataIndex: 'bootTimeSecCount',
width: 100,
align: 'center'
},
{
title: '系統(tǒng)更新時間',
dataIndex: 'osUpdateTimeSecCount',
width: 120,
align: 'center'
},
{
title: '初始化時間',
dataIndex: 'birthTimeCount',
width: 100,
align: 'center'
},
{
title: 'caids',
dataIndex: 'caidsCount',
width: 100,
align: 'center'
},
{
title: '系統(tǒng)編譯時間',
dataIndex: 'sysComplingTimeCount',
width: 120,
align: 'center'
},
{
title: 'IDFA',
dataIndex: 'idfaCount',
width: 100,
align: 'center'
},
{
title: 'IMSI',
dataIndex: 'imsiCount',
width: 100,
align: 'center'
},
{
title: '安裝包列表',
dataIndex: 'appListCount',
width: 120,
align: 'center'
},
{
title: '狀態(tài)',
dataIndex: 'graspingStatus',
scopedSlots: { customRender: 'graspingStatus' },
width: 100,
fixed: 'right',
align: 'center'
},
{
title: '抓取時間',
dataIndex: 'graspingTime',
scopedSlots: { customRender: 'time' },
width: 180,
fixed: 'right'
}
]
}
},
props: {
visible: {
type: Boolean,
default: false
},
mediaAdId: {
type: [Number, String],
required: true
}
},
methods: {
formatDateTime(timeStr) {
return timeStr ? dayjs(timeStr).format('YYYY-MM-DD HH:mm:ss') : '-'
},
getStatusText(status) {
const map = { 0: '失敗', 1: '成功', 2: '部分成功' }
return map[status] || '未知'
},
getStatusColor(status) {
const map = { 0: 'red', 1: 'green', 2: 'orange' }
return map[status] || 'default'
},
handleTableChange(pagination) {
this.pagination.current = pagination.current
this.pagination.pageSize = pagination.pageSize
this.fetchData()
},
async fetchData() {
this.loading = true
try {
const { data: res } = await getGraspingRecords({
mediaAdId: this.mediaAdId,
page: this.pagination.current,
pageSize: this.pagination.pageSize
})
if (res.code === '000000') {
this.data = res.data.aaData || []
this.pagination.total = res.data.iTotalRecords || 0
} else {
throw new Error(res.msg || '獲取數(shù)據(jù)失敗')
}
} catch (error) {
console.error('獲取抓取記錄失敗:', error)
this.$message.error(error.message)
} finally {
this.loading = false
}
},
handleCancel() {
this.$emit('close')
}
}
}
</script>
<style scoped>
.grasping-record-modal >>> .ant-table {
min-width: 100%;
}
.grasping-record-modal >>> .ant-table-container {
overflow-x: auto !important;
}
.grasping-record-modal >>> .ant-table-body {
overflow-x: auto !important;
}
</style>
六、總結(jié)與最佳實踐
通過這個案例,我們總結(jié)出以下Ant Design Table組件的最佳實踐:
1.固定列設(shè)計:
- 關(guān)鍵信息固定在左右兩側(cè)
- 固定列寬度適當(dāng)加大
- 添加
ellipsis防止長文本溢出
2.滾動區(qū)域優(yōu)化:
- 使用
scroll="{ x: 'max-content' }" - 配合CSS強制溢出設(shè)置
- 確保表格寬度自適應(yīng)
3.性能考慮:
- 合理設(shè)置分頁大小
- 使用
loading狀態(tài)提升用戶體驗 - 大數(shù)據(jù)量時考慮虛擬滾動
4.視覺一致性:
- 數(shù)值列居中對齊
- 狀態(tài)使用標(biāo)簽顏色區(qū)分
- 時間統(tǒng)一格式化
5.健壯性保障:
- 數(shù)據(jù)獲取錯誤處理
- 空狀態(tài)處理
- 分頁參數(shù)校驗
這個案例展示了如何通過迭代優(yōu)化解決實際問題,最終實現(xiàn)了一個既美觀又實用的數(shù)據(jù)表格組件。希望這些經(jīng)驗?zāi)軒椭阍谖磥淼捻椖恐懈玫厥褂肁nt Design Table組件。
到此這篇關(guān)于Vue+Ant Design開發(fā)簡單表格組件的實戰(zhàn)指南的文章就介紹到這了,更多相關(guān)Vue Ant Design組件開發(fā)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
web面試MVC與MVVM區(qū)別及Vue為什么不完全遵守MVVM解答
這篇文章主要介紹了web面試中常問問題,MVC與MVVM區(qū)別以及Vue為什么不完全遵守MVVM的難點解答,有需要的朋友可以借鑒參考下,希望能夠有所幫助2021-09-09
一文詳解vue3項目實戰(zhàn)中的接口調(diào)用
在企業(yè)開發(fā)過程中,往往有著明確的前后端的分工,前端負責(zé)接收、使用接口,后端負責(zé)編寫、處理接口,下面這篇文章主要給大家介紹了關(guān)于vue3項目實戰(zhàn)中的接口調(diào)用的相關(guān)資料,需要的朋友可以參考下2022-12-12
詳解在Vue中如何使用axios跨域訪問數(shù)據(jù)
本篇文章主要介紹了在Vue中如何使用axios跨域訪問數(shù)據(jù),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-07-07
解決Vue2?axios發(fā)請求報400錯誤"Error:?Request?failed?with?s
這篇文章主要給大家介紹了關(guān)于如何解決Vue2?axios發(fā)請求報400錯誤"Error:?Request?failed?with?status?code?400"的相關(guān)資料,在Vue應(yīng)用程序中我們通常會使用axios作為網(wǎng)絡(luò)請求庫,需要的朋友可以參考下2023-07-07
Vue組件傳值方式(props屬性,父到子,子到父,兄弟傳值)
這篇文章主要介紹了Vue組件傳值方式(props屬性,父到子,子到父,兄弟傳值),具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-06-06

