vue3+elementplus基于el-table-v2封裝公用table組件詳細(xì)代碼
1.梳理出需要封裝的功能
主要是針對(duì)表格進(jìn)行封裝,不包括查詢表單和操作按鈕。
梳理出系統(tǒng)中通用表格的功能項(xiàng),即表格主體的所有功能,生成columns列頭數(shù)據(jù)、生成data表體數(shù)據(jù)、拖拉列寬、分頁(yè)、生成中文列名、自定義列寬width

效果如下:

2.封裝表格(表格+分頁(yè))
<template>
<slot></slot>
<div class="table-v2">
<el-auto-resizer always height="36">
<!--行高 :row-height="36" -->
<template #default="{ height, width }">
<el-table-v2 :columns="columns" :scrollbar-always-on="true" :data="data" :width="width" :height="height"
:row-height="36" :row-key="data.id" fixed>
</el-table-v2>
</template>
</el-auto-resizer>
<!-- 分頁(yè) -->
<div class="pagination" v-if="showPage">
<el-pagination background class="pagination" layout="prev, pager, next" :current-page="pageNum" :total="total"
:page-size="pageSize" @prev-click="prevClick" @next-click="nextClick" @current-change="currentChange" />
</div>
</div>
</template>父級(jí)引用:
<!-- 表格 -->
<t-table-v2 @handle-pagenation="handlePagenation"></t-table-v2>3.將生成列名和表體數(shù)據(jù)、復(fù)選框、操作按鈕等方法封裝成類
import { unref } from 'vue'
import { ElCheckbox, TableV2FixedDir } from 'element-plus'
export default class GenerateTableData {
// options: {columns:...,data:...}
constructor(data) {
this.data = data;
this.column = this.createColumnsData();
this.rowData = this.createRowsData();
}
/**
* 通過(guò)tableData生成 columnsData
* @returns
*/
createColumnsData = () => {
let columnsData = [];
if (this.data.length > 0) columnsData = Object.keys(this.data[0]);
return columnsData;
}
/**
* 通過(guò)tableData生成 rowsData
* @returns
*/
createRowsData = () => {
let rowData = [];
this.data.map(item => {
rowData.push(Object.values(item));
});
return rowData;
}
/**
* 函數(shù)設(shè)置width屬性值
* @param {*} columnIndex
*/
static calculateWidth = (columnIndex, columnWidth) => {
let tempArr = [];
if (typeof columnWidth === "number") {
return columnWidth;
} else if (typeof columnWidth === "object") {
columnWidth.map((k, index) => {
if (typeof k.columnsIndex === "object") {
k.columnsIndex.map(innerK => {
tempArr.push({ columnsIndex: innerK, width: k.width });
});
} else {
tempArr.push(columnWidth[index]);
}
});
}
let width = 0;
tempArr.map((k) => {
switch (columnIndex) {
case k.columnsIndex:
width = k.width;
break;
}
});
return width;
}
/**
* 將英文列名改為中文列名(id不顯示)
* @param {*} columnIndex
*/
static transferColumnName = (columnIndex, cnColumnNameArr) => {
return cnColumnNameArr[columnIndex];
}
/**
* 隱藏列
* @param {*} columnIndex
*/
static handleHiddenColumns = (columnIndex, hiddenIndex) => {
return hiddenIndex.includes(columnIndex);
}
/**
* 生成列名: cnColumnNameArr有值則使用中文名,無(wú)值使用原this.column值
* @param {*} columnsArr
*/
generateColumns(cnColumnNameArr, hiddenIndex, columnWidth) {
console.log(cnColumnNameArr, this.column);
if (cnColumnNameArr) this.column = cnColumnNameArr;
return this.column.map((item, columnIndex) => {
return {
key: `${item}`,
dataKey: `${item}`,
title: `${item}`,
// 通過(guò)函數(shù)設(shè)置width值
hidden: hiddenIndex.length > 0 ? GenerateTableData.handleHiddenColumns(columnIndex, hiddenIndex) : false,
width: GenerateTableData.calculateWidth(columnIndex, columnWidth),
align: 'center',
};
})
}
// 生成列表數(shù)據(jù)
generateData = (columns) => {
return this.rowData.map((item, rowIndex) => {
return columns.reduce(
(rowData, column, columnIndex) => {
// item數(shù)組下標(biāo)columnIndex-1開(kāi)始(id不顯示),因?yàn)橛衏heckbox復(fù)選框
rowData[column.dataKey] = item[columnIndex];
return item;
},
// 初始化元素為第一條數(shù)據(jù)(否則數(shù)據(jù)會(huì)獲取不到id)tempDataArr[0]
this.rowData[rowIndex]
)
})
}
/**
* 增加全選列且操作全選/全不選 ; 增加操作按鈕:修改,刪除
* @param {*} columns
*/
static customizeColumns = (columns, data, selectedId, cellRendererFunc) => {
// 全選按鈕:在數(shù)組頭部添加
columns.unshift({
key: 'selection',
dataKey: 'selection',
title: 'selection',
width: 30,
cellRenderer: ({ rowData }) => {
// 綁定數(shù)據(jù)的id,然后row-key才能使用id
rowData.id = rowData[0];
const onChange = (value) => {
rowData.checked = value
if (rowData.checked) {
selectedId.push(rowData[0]);
} else {
let idIndex = selectedId.findIndex(item => item === rowData[0]);
selectedId.splice(idIndex, 1);
}
console.log("selectedId.value------------", selectedId);
return rowData.checked;
}
return ( <
ElCheckbox onChange = { onChange }
modelValue = { rowData.checked }
indeterminate = { false }
/>
)
},
headerCellRenderer: () => {
const _data = unref(data)
const onChange = (value) =>
(data = _data.map((row) => {
row.checked = value;
// 全選id設(shè)置
if (row.checked) {
selectedId.push(row[0]);
} else {
selectedId = [];
}
return row;
}))
// 全選
const allSelected = _data.every((row) => row.checked)
// 非全選
const containsChecked = _data.some((row) => row.checked)
return ( <
ElCheckbox onChange = { onChange }
modelValue = { allSelected }
indeterminate = { containsChecked && !allSelected }
/>
)
},
});
// 操作按鈕:在數(shù)組末尾添加
cellRendererFunc && columns.push({
key: 'operations',
dataKey: 'operations',
title: '操作',
width: 300,
align: 'center',
// 編輯和刪除操作:綁定當(dāng)前id,使用的是JSX語(yǔ)法,方法調(diào)用onClick={ editResource } 傳參:onClick={ (event)=>editResource(rowData[0]) }
cellRenderer: ({ rowData }) => cellRendererFunc(rowData)
});
};
/**
* 固定列:可以用這個(gè)方法也可以用elementplus自帶的(自帶的感覺(jué)還方便一些)
*/
fixedColumns = (columns, fixedColumnIndex) => {
fixedColumnIndex.length > 0 && fixedColumnIndex.map(column => {
// 不設(shè)置為T(mén)ableV2FixedDir.LEFT這種形式,可以直接寫(xiě)true,默認(rèn)left
let tableV2Fixed = true;
if (column.direction === "left") tableV2Fixed = TableV2FixedDir.LEFT;
if (column.direction === "right") tableV2Fixed = TableV2FixedDir.RIGHT;
columns[column.index].fixed = tableV2Fixed;
});
}
}4.父類中調(diào)用類方法
// 數(shù)據(jù)所有列都一樣,所以取第一條數(shù)據(jù)列名作為表頭
let cnColumnNameArr = ['編號(hào)', '資源名稱', '資源類型', '提交原因', '上個(gè)投產(chǎn)版本', '投產(chǎn)版本', '提交人', 'SIT'
, '提交時(shí)間', '狀態(tài)', 'SIT部署時(shí)間', 'SIT測(cè)試完成時(shí)間', 'UAT部署時(shí)間', 'SIT部署完成', 'SIT已測(cè)試', 'UAT部署完成'];
let hiddenIndex = [0,4];
let columnWidth = [{columnsIndex:[0,4],width:0},
{columnsIndex:1,width:146},
{columnsIndex:2,width:80},
{columnsIndex:3,width:300},
{columnsIndex:5,width:76},
{columnsIndex:[6,9],width:100},
{columnsIndex:[8,10,11,12],width:160},
{columnsIndex:[7,13,14,15],width:70},
{columnsIndex:'default',width:58}];
const generateTableData = new GenerateTableData(tableData.value);
// 完全無(wú)值也需要顯示列名, cnColumnNameArr此處必須有值:cnColumnNameArr或者false(英文列名)
cnColumnNameArr = tableData.value.length === 0? cnColumnNameArr : cnColumnNameArr;//length如果不為0是設(shè)置為false就會(huì)顯示英文列名
columns.value = generateTableData.generateColumns(cnColumnNameArr,hiddenIndex,columnWidth);
// 設(shè)置全選按鈕和操作按鈕
data.value = code === 200 ? generateTableData.generateData(columns.value): [];
GenerateTableData.customizeColumns(columns.value,data.value,selectedId.value,cellRenderer);
if(code === 200){
// 固定列
columns.value[0].fixed = true
columns.value[1].fixed = TableV2FixedDir.LEFT
columns.value[2].fixed = TableV2FixedDir.LEFT
columns.value[3].fixed = TableV2FixedDir.LEFT
}
resizeColumns(columns.value);5.父子組件通信(provide/inject)
父組件:
// provide方式父子組件傳值
provide('columns', computed(()=>columns.value));
provide('data', computed(()=>data.value));
// 分頁(yè)
provide('showPage', computed(()=>true));
provide('pageNum', computed(()=>pageNum.value));
provide('total', computed(()=>total.value));
provide('pageSize', computed(()=>pageSize.value));
provide('pages', computed(()=>pages.value));
// 是否寬高自適應(yīng)
provide('selfAdaption', computed(()=>true));
provide('cellRenderer', computed(()=>cellRenderer));子組件:
// 是否顯示分頁(yè)組件
const showPage = inject('showPage',false);
const columns = inject('columns',[]);
const data = inject('data',[]);
const pageNum = inject('pageNum',1);
const pages = inject('pages',0);
const total = inject('total',0);
const pageSize = inject('pageSize',16);
// 是否寬高自適應(yīng)
const selfAdaption = inject('selfAdaption',false);6.分頁(yè)
子組件:
const $emit = defineEmits(['handlePagenation']);
/**
* 上一頁(yè):pageNum會(huì)自動(dòng)-1
*/
const prevClick = () => {
// pageNation分頁(yè)組件限定,pageNum.value不可能為0;如果pageNum.value比1大就取pageNum.value,否則永遠(yuǎn)為1
$emit('handlePagenation', Math.max(1, pageNum.value));
}
/**
* 下一頁(yè):pageNum會(huì)自動(dòng)+1
*/
const nextClick = () => {
// 如果pageNum.value比pages小就取pageNum.value,否則永遠(yuǎn)為pages
$emit('handlePagenation', Math.max(1, Math.min(pages.value, pageNum.value)));
}
/**
* 點(diǎn)擊特定頁(yè)碼(此方法會(huì)自動(dòng)傳入當(dāng)前頁(yè)碼)
* @param {*} currentPage
*/
const currentChange = (currentPage) => {
$emit('handlePagenation', currentPage);
}父組件:
/**
* 分頁(yè)
*/
const handlePagenation = (pageNumVal) =>{
// pageNation分頁(yè)組件限定,pageNum.value不可能為0;如果pageNum.value比1大就取pageNum.value,否則永遠(yuǎn)為1
pageNum.value = pageNumVal;
loadDataGrid();
}7.問(wèn)題:el-table-v2中數(shù)據(jù)失去響應(yīng)性

以上,實(shí)現(xiàn)簡(jiǎn)單封裝
總結(jié)
到此這篇關(guān)于vue3+elementplus基于el-table-v2封裝公用table組件的文章就介紹到這了,更多相關(guān)el-table-v2封裝公用table組件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue如何通過(guò)$router.push傳參數(shù)
這篇文章主要介紹了vue如何通過(guò)$router.push傳參數(shù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06
解決微信瀏覽器緩存站點(diǎn)入口文件(IIS部署Vue項(xiàng)目)
這篇文章主要介紹了解決微信瀏覽器緩存站點(diǎn)入口文件(IIS部署Vue項(xiàng)目),本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-06-06
Vue實(shí)現(xiàn)控制商品數(shù)量組件封裝及使用
這篇文章主要為大家詳細(xì)介紹了Vue實(shí)現(xiàn)控制商品數(shù)量組件的封裝及使用,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09
Vue的路由及路由鉤子函數(shù)的實(shí)現(xiàn)
這篇文章主要介紹了Vue的路由及路由鉤子函數(shù)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07
使用Vue-cli3.0創(chuàng)建的項(xiàng)目 如何發(fā)布npm包
這篇文章主要介紹了使用Vue-cli3.0創(chuàng)建的項(xiàng)目,如何發(fā)布npm包,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-10-10
Vue.js通用應(yīng)用框架-Nuxt.js的上手教程
本篇文章主要介紹了Vue.js通用應(yīng)用框架-Nuxt.js的上手教程,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-12-12
iView UI FORM 動(dòng)態(tài)添加表單項(xiàng)校驗(yàn)規(guī)則寫(xiě)法實(shí)例
這篇文章主要為大家介紹了iView UI FORM 動(dòng)態(tài)添加表單項(xiàng)校驗(yàn)規(guī)則寫(xiě)法實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01

