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ā)一個媒體廣告抓取記錄查看功能,主要需求包括:
- 展示媒體廣告位的抓取記錄數(shù)據(jù)
- 支持分頁和排序功能
- 關鍵信息需要固定顯示(左右兩側(cè))
- 中間區(qū)域可橫向滾動查看更多數(shù)據(jù)字段
- 良好的性能表現(xiàn),支持大數(shù)據(jù)量
基于這些需求,我們選擇了Ant Design Vue作為UI組件庫,其強大的Table組件非常適合這類需求。
二、基礎實現(xiàn)
2.1 組件結(jié)構(gòu)設計
首先我們創(chuàng)建了GraspingRecordModal.vue
組件,基礎結(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è)的關鍵信息:
columns: [ { title: '任務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)了幾個關鍵問題:
- 寬度計算不準確:固定列和非固定列的寬度總和與表格容器寬度不匹配
- 滾動設置不當:
scroll.x
值設置不合理 - CSS樣式?jīng)_突:Ant Design默認樣式與我們的需求有沖突
3.3 初步修復嘗試
我們首先嘗試調(diào)整列寬和滾動設置:
:scroll="{ x: 1800 }" // 根據(jù)列寬總和設置固定值
同時調(diào)整了一些列的寬度:
{ title: '任務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: '任務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 關鍵優(yōu)化點
- 使用’max-content’:讓表格根據(jù)內(nèi)容自動計算寬度
- 強制溢出設置:確保滾動行為符合預期
- 最小寬度保證:防止容器意外收縮
- 列對齊統(tǒng)一:所有數(shù)值列居中對齊
- 固定列優(yōu)化:左右兩側(cè)固定列寬度適當加大
五、完整優(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: '任務ID', dataIndex: 'graspingTaskId', width: 180, fixed: 'left', ellipsis: true }, { title: '總?cè)罩緮?shù)', dataIndex: 'totalCount', width: 100, fixed: 'left', align: 'center' }, { title: '設備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.固定列設計:
- 關鍵信息固定在左右兩側(cè)
- 固定列寬度適當加大
- 添加
ellipsis
防止長文本溢出
2.滾動區(qū)域優(yōu)化:
- 使用
scroll="{ x: 'max-content' }"
- 配合CSS強制溢出設置
- 確保表格寬度自適應
3.性能考慮:
- 合理設置分頁大小
- 使用
loading
狀態(tài)提升用戶體驗 - 大數(shù)據(jù)量時考慮虛擬滾動
4.視覺一致性:
- 數(shù)值列居中對齊
- 狀態(tài)使用標簽顏色區(qū)分
- 時間統(tǒng)一格式化
5.健壯性保障:
- 數(shù)據(jù)獲取錯誤處理
- 空狀態(tài)處理
- 分頁參數(shù)校驗
這個案例展示了如何通過迭代優(yōu)化解決實際問題,最終實現(xiàn)了一個既美觀又實用的數(shù)據(jù)表格組件。希望這些經(jīng)驗能幫助你在未來的項目中更好地使用Ant Design Table組件。
到此這篇關于Vue+Ant Design開發(fā)簡單表格組件的實戰(zhàn)指南的文章就介紹到這了,更多相關Vue Ant Design組件開發(fā)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
web面試MVC與MVVM區(qū)別及Vue為什么不完全遵守MVVM解答
這篇文章主要介紹了web面試中常問問題,MVC與MVVM區(qū)別以及Vue為什么不完全遵守MVVM的難點解答,有需要的朋友可以借鑒參考下,希望能夠有所幫助2021-09-09一文詳解vue3項目實戰(zhàn)中的接口調(diào)用
在企業(yè)開發(fā)過程中,往往有著明確的前后端的分工,前端負責接收、使用接口,后端負責編寫、處理接口,下面這篇文章主要給大家介紹了關于vue3項目實戰(zhàn)中的接口調(diào)用的相關資料,需要的朋友可以參考下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
這篇文章主要給大家介紹了關于如何解決Vue2?axios發(fā)請求報400錯誤"Error:?Request?failed?with?status?code?400"的相關資料,在Vue應用程序中我們通常會使用axios作為網(wǎng)絡請求庫,需要的朋友可以參考下2023-07-07Vue組件傳值方式(props屬性,父到子,子到父,兄弟傳值)
這篇文章主要介紹了Vue組件傳值方式(props屬性,父到子,子到父,兄弟傳值),具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-06-06