Element實現(xiàn)動態(tài)表格的示例代碼
【代碼背景】
有這樣一個業(yè)務(wù)需求場景,有大概十幾張表歸屬于某個類別,用戶希望在同一個頁面,通過選擇不同的查詢指標(biāo)展示不同的表格,這些表的表頭樣式類似但是又不完全相同,怎么做呢?
到目前為止所有基于Element UI的表格樣式都是直接在頁面寫死的,像官方這樣:
<el-table :data="tableData" style="width: 100%">
<el-table-column prop="date" label="日期" width="180"></el-table-column>
<el-table-column prop="name" label="姓名" width="180"></el-table-column>
<el-table-column prop="address" label="地址"></el-table-column>
</el-table>
要解決上述問題,最簡單暴力的方式是為每個表寫一個單獨組件,然后通過select框觸發(fā)事件切換不同組件路由渲染頁面,當(dāng)然這種方式很笨,也不符合代碼復(fù)用的基本原則,所以為了偷懶,為了堅守代碼復(fù)用的基本原則,開始思考有沒有更好的方式來解決這個問題。
仔細(xì)觀察這個<el-table>,表格數(shù)據(jù)是通過:data綁定的,表格頭部數(shù)據(jù)則是通過<el-table-column>標(biāo)簽展示的,表頭數(shù)據(jù)是不是也可以通過某種傳參的方式結(jié)合v-for來渲染<el-table-column>的具體數(shù)據(jù)呢?在度娘的幫助下,果然有大佬已經(jīng)這樣做了,實現(xiàn)了動態(tài)表格,參考鏈接掛在最底下了哦,在此特別感謝免費分享知識的大佬們,知識無價,學(xué)無止境。
現(xiàn)將本項目的具體實現(xiàn)代碼記錄如下,完善了一些代碼的注解,嘗試幫助理解。
【代碼實現(xiàn)】
#1# -> 代碼復(fù)用的基礎(chǔ)是你需要一個可復(fù)用的組件
在/components/Table文件夾下新建兩個組件
DynamicTable.vue
<template>
<!-- 動態(tài)展示表格 -->
<el-table :data="tableData" border stripe :height="height" @row-click="handleRowClick">
<!-- v-for 循環(huán)取表頭數(shù)據(jù) -->
<template v-for="item in tableHeader">
<table-column v-if="item.children && item.children.length" :key="item.id" :column-header="item" />
<el-table-column v-else :key="item.id" :label="item.label" :prop="item.prop" align="center" />
</template>
</el-table>
</template>
<script>
import TableColumn from '@/components/Table/TableColumn'
export default {
name: 'DynamicTable',
components: {
TableColumn
},
props: {
// 表格的數(shù)據(jù)
tableData: {
type: Array,
required: true
},
// 多級表頭的數(shù)據(jù)
tableHeader: {
type: Array,
required: true
},
// 表格的高度
height: {
type: String,
default: '300'
}
},
methods: {
// 行點擊事件
handleRowClick (row, column, event) {
// console.log(row)
// console.log(column)
// console.log(event)
// 通知調(diào)用父組件的row-click事件
// row作為參數(shù)傳遞過去
this.$emit('row-click', row)
}
}
}
</script>
TableColumn.vue
<template>
<el-table-column
:label="columnHeader.label"
:prop="columnHeader.label"
align="center"
>
<!--columnHeader對應(yīng):column-header-->
<template v-for="item in columnHeader.children">
<tableColumn
v-if="item.children && item.children.length"
:key="item.id"
:column-header="item"
/>
<el-table-column
v-else
:key="item.name"
:label="item.label"
:prop="item.prop"
align="center"
/>
</template>
</el-table-column>
</template>
<script>
export default {
name: 'TableColumn',
props: {
columnHeader: {
type: Object,
required: true
}
}
}
</script>
<style scoped>
</style>
幾點重要說明:
(1)表格頭部的傳參主要分為兩類:帶children節(jié)點和不帶children節(jié)點的,如下圖所示

請注意children節(jié)點是為了完成復(fù)雜表頭的渲染,例如上面這個示例最終的表頭渲染樣式如下:

那么問題來了,<el-table-column>是<el-table>的標(biāo)簽,那這個<table-column>是個啥?
(2)DynamicTable.vue調(diào)用TableColumn.vue組件

DynamicTable.vue通過:column-header給TableColumn.vue傳遞帶children子節(jié)點的表頭信息,TableColumn.vue接收到這個節(jié)點信息后,主要做了以下兩件事情:
第一:通過<el-table-column>渲染了一個label標(biāo)簽
第二:繼續(xù)判斷該節(jié)點是否存在children子節(jié)點
=> 如果存在children節(jié)點,繼續(xù)通過<table-column>進(jìn)行渲染,繼續(xù)把這個子節(jié)點傳給TableColumn.vue組件,重復(fù)上述步驟
=> 如果不存在children節(jié)點,表示這是一個終止節(jié)點,通過<el-table-column>渲染結(jié)束
#2# -> 在展示頁面使用動態(tài)表格組件
<template>
<div class="demo">
<el-card>
<!--查詢區(qū)域-->
<el-row :gutter="10">
<el-col :span="6">
<div class="grid-content bg-purple">
<span style="margin-right: 10px">選擇框 -</span>
<el-select
v-model="specified_table"
placeholder="請選擇"
>
<el-option
v-for="item in options"
:key="item.zb_code"
:label="item.zb_name"
:value="item.zb_code"
/>
</el-select>
</div>
</el-col>
<el-col :span="6">
<div class="grid-content bg-purple">
<el-button type="primary" plain @click="handleQueryClick">查 詢</el-button>
</div>
</el-col>
</el-row>
<!--表格區(qū)域-->
<dynamic-table
v-if="dynamicTableShow"
:table-data="tableData"
:table-header="tableHeaders"
:height="'550px'"
/>
</el-card>
</div>
</template>
<script>
// 引入組件
import DynamicTable from '@/components/Table/DynamicTable'
// 獲取表頭信息
import { getTableHeader02_1, getTableHeader02_2, getTableHeader02_3, getTableHeader02_4 } from '@/api/table-header'
export default {
name: 'Index',
components: { // 組件注冊
DynamicTable
},
data () {
return {
// -- 查詢 ----------------------
options: [
// { zb_name: '指標(biāo)名', zb_code: '指標(biāo)代碼' }
],
specified_table: '', // 指標(biāo)值
// -- 表格 ----------------------
dynamicTableShow: true, // DynamicTable組件重新渲染變量
// 表頭數(shù)據(jù)
tableHeaders: [],
// 表格數(shù)據(jù)
tableData: []
}
},
created () {
// api-獲取指標(biāo)的下拉框數(shù)據(jù)
getSpecifiedTable().then(res => {
this.options = res.data
})
},
methods: {
// 判斷值是否在數(shù)組中
isExistArr (arr, val) {
return arr.includes(val)
},
// 重新渲染表格
refreshTable (zb_code) {
// 根據(jù)value值獲取label值
const obj = this.options.find((item) => {
return item.zb_code === zb_code
})
console.log(zb_code)
console.log(obj.zb_name)
// 設(shè)置dynamicTableShow為false,使得DynamicTable組件重新渲染
this.dynamicTableShow = false
// 根據(jù)不同指標(biāo)渲染不同的表頭
const TBArr01 = ['M01', 'M02', 'M03', 'M05'] // 第1類表
const TBArr02 = ['M04', 'M07', 'M08', 'M12'] // 第2類表
const TBArr03 = ['M09', 'M10', 'M11'] // 第3類表
const TBArr04 = ['M06'] // 第4類表
if (this.isExistArr(TBArr01, zb_code)) {
this.tableHeaders = getTableHeader02_1(obj.zb_name) // 渲染表頭樣式1
}
if (this.isExistArr(TBArr02, zb_code)) {
this.tableHeaders = getTableHeader02_2(obj.zb_name) // 渲染表頭樣式2
}
if (this.isExistArr(TBArr03, zb_code)) {
this.tableHeaders = getTableHeader02_3(obj.zb_name) // 渲染表頭樣式3
}
if (this.isExistArr(TBArr04, zb_code)) {
this.tableHeaders = getTableHeader02_4(obj.zb_name) // 渲染表頭樣式4
}
// api - 獲取表格數(shù)據(jù)
getTableList02(zb_code).then(res => {
this.tableData = res.data
})
// 此處是DOM還沒有更新,此處的代碼是必須的
this.$nextTick(() => {
// DOM現(xiàn)在更新了
this.dynamicTableShow = true
})
},
// 點擊[查詢]事件
handleQueryClick () {
const zb_code = this.specified_table
// 校驗查詢條件不能為空
if (zb_code === '' || zb_code === undefined) {
this.$message.warning('指標(biāo)不能為空!')
} else {
console.log('zb_code: ' + zb_code)
// 重新渲染表頭和表格
this.refreshTable(zb_code)
}
}
}
}
</script>
使用動態(tài)表格組件相對來說比較簡單,唯一需要注意的地方是,渲染表格頭部跟數(shù)據(jù)時必須需要添加以下代碼,不然頁面無法按照預(yù)期完成渲染。
this.$nextTick(() => {
// DOM現(xiàn)在更新了
this.dynamicTableShow = true
})
關(guān)于this.$nextTick()可以參考官網(wǎng):https://cn.vuejs.org/v2/guide/reactivity.html

#3# -> 如何給動態(tài)表格根據(jù)需求動態(tài)添加序號列/索引列
在Element UI官方例子中,如果需要給table添加一個序號列或者索引列非常簡單,直接在<el-table>里聲明一個特殊的<el-table-column>即可。
<el-table-column type="index" width="50"></el-table-column>
那如何在動態(tài)表格組件里添加序號列呢?更甚者如果根據(jù)需要自行添加或者不添加?
首先我們來改造 DynamicTable.vue
像官方例子一樣,我們先在<el-table>里也聲明一個<el-table-column>
<el-table-column v-if="isIndex" type="index" width="100" label="序號" align="center" />
注意到這里有一個v-if綁定了一個isIndex值,這個值就是我們需要在父組件進(jìn)行傳值的關(guān)鍵了
在props里聲明isIndex為Boolean類型
props: {
// 表格的數(shù)據(jù)
tableData: {
type: Array,
required: true
},
// 多級表頭的數(shù)據(jù)
tableHeader: {
type: Array,
required: true
},
// 表格的高度
height: {
type: String,
default: '300'
},
// 是否需要添加序號列
isIndex: {
type: Boolean
}
}
在展示頁面使用組件時通過:is-index傳入指定參數(shù)
<dynamic-table
v-if="dynamicTableShow"
:table-data="tableData"
:table-header="tableHeaders"
:height="'550px'"
:is-index="true"
/>
在同頁面表頭需要切換的情況下,上面這種寫法容易在頁面初始化時候單獨顯示一個序號列,就像下面這樣,非常不美觀

我希望序號列可以和其他普通列一樣在表頭渲染的時候同時加載,可以這樣做
<dynamic-table
v-if="dynamicTableShow"
:table-data="tableData"
:table-header="tableHeaders"
:height="'550px'"
:is-index="isAddIndex"
/>
將原本的常量“true”修改成一個變量isAddIndex替代,然后在表頭渲染完成的時候?qū)⑵渲敌薷某蓆rue
this.isAddIndex = true
這樣序號列就能跟其他普通列同時進(jìn)行渲染了。
【參考資料】
https://www.jianshu.com/p/9c4ba833658f
https://www.cnblogs.com/llcdxh/p/9473458.html
到此這篇關(guān)于Element實現(xiàn)動態(tài)表格的示例代碼的文章就介紹到這了,更多相關(guān)Element 動態(tài)表格內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue?axios?form-data格式傳輸數(shù)據(jù)和文件方式
這篇文章主要介紹了vue?axios?form-data格式傳輸數(shù)據(jù)和文件方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-05-05
vue環(huán)形進(jìn)度條組件實例應(yīng)用
在本文中我們給大家分享了關(guān)于vue環(huán)形進(jìn)度條組件的使用方法以及實例代碼,需要的朋友們跟著測試下吧。2018-10-10
element vue Array數(shù)組和Map對象的添加與刪除操作
這篇文章主要介紹了element vue Array數(shù)組和Map對象的添加與刪除功能,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2018-11-11

