Vue業(yè)務(wù)組件封裝Table表格示例詳解
前言
這個系列主要是分享自己在工作中常用到的業(yè)務(wù)組件,以及如何對這些組件進行有效的封裝和封裝的思路。注:都是基于element ui進行二次封裝。
封裝組件的基本方法就是通過props和emit進行父子組件的傳值和通信。利用插槽、組件等去增加組件的可擴展性和復(fù)用性。
Table組件介紹
用于展示多條結(jié)構(gòu)類似的數(shù)據(jù),可對數(shù)據(jù)進行排序、篩選、對比或其他自定義操作。table組件常用于后臺管理系統(tǒng),基本上是后臺管理系統(tǒng)中使用頻率最高的組件了,一個table組件具有最基本的功能就是crud。

基本的table
Table組件封裝思路
了解element Table組件代碼
這里以最基本的Table代碼為例進行分析:
<template>
<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>
</template>
<script>
export default {
data() {
return {
tableData: [{
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀區(qū)金沙江路 1518 弄'
}, {
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀區(qū)金沙江路 1517 弄'
}, {
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀區(qū)金沙江路 1519 弄'
}, {
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀區(qū)金沙江路 1516 弄'
}]
}
}
}
</script>

table樣式
根據(jù)基本的Table代碼,我們可以知道:
- Table渲染的數(shù)據(jù)是一個數(shù)組,數(shù)組的每一項包含了每一列的信息,然后綁定到el-table的data屬性里面。
- el-table-column為Table一行中每列的內(nèi)容,一行有多少列,就寫多少個el-table-column。
- 每個el-table-column中綁定了prop、label屬性,他們分別對應(yīng)data數(shù)據(jù)里所渲染出來的內(nèi)容和每列的表頭文字,注意prop的值一定要與tableData里的對象屬性相同。
Table組件如何去封裝
通過分析Table代碼我們可以把el-table-column里面綁定的屬性抽離出一個配置文件,通過對配置文件的遍歷得到所有el-table-column。
配置文件代碼實現(xiàn)
新建LTable組件
我們在components文件夾下新建一個LTable表示我們封裝的Table組件。基于Table組件的基本代碼,我們寫下LTable下代碼內(nèi)容:
<template>
<div>
<el-table :data="tableData" border style="width: 100%">
<el-table-column type="index" align="center" width="50" v-if="showIndexColumn">
</el-table-column>
<el-table-column type="selection" align="center" width="55" v-if="showSelectColumn">
</el-table-column>
<template v-for="item in columnList">
<el-table-column :key="item.prop" align="center" v-bind="item">
</el-table-column>
</template>
</el-table>
</div>
</template>
<script>
export default {
props: {
columnList: {
type: Array,
default: () => []
},
showIndexColumn: {
type: Boolean,
default: false
},
showSelectColumn: {
type: Boolean,
default: false
},
requestUrl: {
type: String,
require: true
}
},
created() {
this.getData();
},
data() {
return {
tableData: [],
// defaultSlotList: ["action"]
};
},
computed: {
isDefaultSlot() {
return function(slotName) {
return this.defaultSlotList.includes(slotName);
};
}
},
methods: {
getData() {
this.api.get(this.requestUrl).then(res => {
this.tableData = res.dataList
})
},
// handleEdit(row) {
// console.log(row);
// },
// handleDelete(row) {
// console.log(row);
// }
}
};
</script>
在組件中我們需要父組件傳入一個columnList,也就是前面我們說的配置文件,table的數(shù)據(jù)我們在LTable里獲取,不用父組件傳遞過來。這樣做的好處是:將通過接口獲取table數(shù)據(jù)統(tǒng)一在LTable管理,減少父組件獲取接口數(shù)據(jù)然后傳遞給LTable的重復(fù)代碼邏輯。相應(yīng)我們需要傳遞請求數(shù)據(jù)的接口地址。
配置文件
新建一個配置文件tableConfig.js,導(dǎo)出文件內(nèi)容,然后再需要用到的頁面引入。
export const tableConfig = {
columnList: [
{
label: "日期",
prop: "date",
sortable: true //對表格進行排序
},
{
label: "圖片", //文字
prop: "imgSrc", //渲染數(shù)據(jù)對應(yīng)的屬性
width: "180" //每列對應(yīng)寬度
},
{
label: "姓名",
prop: "name"
},
{
label: "地址",
prop: "address"
}
],
showIndexColumn: true, //是否顯示table索引
showSelectColumn: true, //是否顯示選擇多行
requestUrl: "api/getData" //接口請求地址
};
頁面內(nèi)容:
<template>
<div class="app-container">
<l-table v-bind="tableConfig"></l-table>
</div>
</template>
<script>
import { tableConfig } from "./config/tableConfig.js";
export default {
components: { LTable: () => import("@/components/LTable") },
data() {
return {
tableConfig
};
},
mounted() {},
methods: {}
};
</script>

table效果
這樣,一個基本的Table封裝就完成了,可以看到我們在頁面中的代碼是非常少的,只有引入了組件,然后將配置文件綁定到組件上就可以了。
不過目前寫的配置都是非常簡單的,如果遇到復(fù)雜的表格內(nèi)容,我們怎么辦?
配置插槽
剛剛完成的小案例我們發(fā)現(xiàn)圖片是直接顯示了地址,那我們想展示圖片怎么辦,一般表格還會有操作列,我們怎么展示出來呢?
這種我們不能直接渲染數(shù)據(jù),而是需要轉(zhuǎn)換,比較靈活得到我們想要的的內(nèi)容就需要用到插槽了。
首先我們需要在配置文件增加插槽的選項,我們這里取名slotName:
columnList: [
{
label: "日期",
prop: "date",
Sortable: true
},
{
label: "圖片",
prop: "imgSrc",
width: "180",
slotName: "img"
},
{
label: "姓名",
prop: "name"
},
{
label: "地址",
prop: "address"
},
{
label: "操作",
prop: "action",
slotName: "action"
}
],
對應(yīng)的LTable組件里面的渲染邏輯我們也需要調(diào)整,改為有插槽和沒有插槽兩種情況去渲染。表格里的插槽有些在所有表格里面都會用到比如操作,這種我們就當(dāng)做默認(rèn)插槽,寫在LTabl里面。
不是每個表格都需要用到插槽就是動態(tài)插槽了,放在對應(yīng)的頁面里。
LTable增加插槽的代碼:
<template>
<div>
<el-table :data="tableData" border style="width: 100%">
// 帶有索引列
<el-table-column type="index" align="center" width="50" v-if="showIndexColumn">
</el-table-column>
// 多選列
<el-table-column type="selection" align="center" width="55" v-if="showSelectColumn">
</el-table-column>
<template v-for="item in columnList">
<el-table-column :key="item.prop" v-if="item.slotName" v-bind='item' align="center">
<template slot-scope="scope">
<!-- 動態(tài)插槽 -->
<slot v-if="!isDefaultSlot(item.slotName)" :name="item.slotName"
:row="scope.row">
</slot>
<!-- 默認(rèn)插槽 -->
<slot v-else name="action">
<el-button size="mini" @click="handleEdit(scope.row)">編輯</el-button>
<el-button size="mini" type="danger" @click="handleDelete(scope.row)">刪除</el-button>
</slot>
</template>
</el-table-column>
// 直接渲染列
<el-table-column v-else :key="item.prop" align="center" v-bind='item'>
</el-table-column>
</template>
</el-table>
</div>
</template>
頁面里面動態(tài)插槽內(nèi)容:
<template>
<div class="app-container">
<l-table v-bind="tableConfig">
<template #img="scope">
<el-image
style="width: 100px; height: 100px"
:src="scope.row.imgSrc"
:preview-src-list="[scope.row.imgSrc]"
fit="cover"
preview-teleported
></el-image>
</template>
</l-table>
</div>
</template>
渲染出來的表格:

帶有插槽表格
這樣,我們就通過配置文件搭配插槽完成了Table組件的封裝,我們可以自由靈活的顯示我們表格里的內(nèi)容。但同時,我們也發(fā)現(xiàn),當(dāng)我們LTable組件里涉及到的插槽越來越多的時候,里面的代碼也會越來越多。隨著我們的項目越來越復(fù)雜,需要的插槽可能有幾十個甚至上百個,使用插槽的方式進行封裝開始顯示出了很多問題。我們該如何對這種情況進行優(yōu)化呢?
動態(tài)組件
解決插槽存在的問題
針對上面提出的問題,我從自動化的角度進行了思考,放棄了大量使用插槽,改用組件代替插槽的形式進行優(yōu)化。將插槽的類型進行匯總,分別定義不同類型的組件去替換插槽,大大減少了由插槽產(chǎn)生的代碼。
代碼實現(xiàn)
首先在配置文件里面添加了type屬性,表示它對應(yīng)哪個動態(tài)組件。還添加了cb回調(diào)函數(shù),主要處理對數(shù)據(jù)的格式進行轉(zhuǎn)化。
export const tableConfig = {
columnList: [
{
type: "text",
label: "日期",
prop: "date",
width: "180"
},
{
type: "image",
label: "圖片",
prop: "imgSrc",
width: "180"
},
{
type: "text",
label: "姓名",
prop: "name"
},
{
type: "function",
label: "性別",
prop: "sex",
sortable: true,
cb: data => {
return data == 1 ? "男" : "女";
}
},
{
type: "input",
label: "地址",
prop: "address"
},
{
type: "slot",
label: "操作",
prop: "action",
slotName: "actions"
}
],
showIndexColumn: true,
showSelectColumn: true,
requestUrl: "api/getData"
};
然后在LTable組件里面做自動化處理,這里需要用到Node里面的require.context方法,他會遞歸獲取相應(yīng)文件夾下的對應(yīng)類型文件。
所以我們還需要在相應(yīng)文件夾下面創(chuàng)建相應(yīng)的組件,這里我是在components文件夾下創(chuàng)建了control文件夾,control文件夾下放我們對應(yīng)需要渲染的組件,這里我創(chuàng)建了四個,function、image、input、text,分別對應(yīng)內(nèi)容需要轉(zhuǎn)化、圖片展示、最基本文字、輸入框。根據(jù)具體的業(yè)務(wù)創(chuàng)建不同的組件即可。

control文件夾
我們需要用require.context方法在LTable組件里拿到control文件夾下的所有組件。
const modules = {};
const files = require.context("../control", true, /\index.vue$/);
files.keys().forEach(item => {
const name = item.split("/")[1];
modules[`com-${name}`] = files(item).default;
});
console.log(modules, 'modules');

打印modules
注冊組件:
components: {
...modules
},
我們通過動態(tài)組件的方式,根據(jù)我們要渲染的表格內(nèi)容去加載不同的組件:
<el-table-column
v-for="item in columnList"
:key="item.prop"
v-bind="item"
align="center"
>
<template slot-scope="scope">
<slot
v-if="item.type === 'slot'"
:name="item.slotName"
:row="scope.row"
></slot>
<components
v-else
:row="scope.row"
:prop="item.prop"
:config="item"
:is="`com-${item.type}`"
></components>
</template>
</el-table-column>
頁面里面的內(nèi)容:
<template>
<div class="app-container">
<automation-table v-bind="tableConfig">
<template #actions="scope">
<el-button @click="handleClick(scope.row)" type="text" size="small"
>查看</el-button
>
<el-button type="text" size="small">編輯</el-button>
</template>
</automation-table>
</div>
</template>
最后,我們在control文件夾下,給定義的組件寫上渲染邏輯:
function組件:
<template>
<div>
{{ config.cb && config.cb(row[prop]) }}
</div>
</template>
<script>
export default {
props: {
row: {
type: Object,
require: true
},
prop: {
type: String,
require: true
},
config: {
type: Object,
require: true
}
},
data() {
return {};
}
};
</script>
<style lang="scss" scoped></style>
主要調(diào)用配置文件里的cb,傳入表格內(nèi)容作為參數(shù),進行我們想要的內(nèi)容轉(zhuǎn)化。
image組件:
<template>
<div>
<el-image
style="width: 70px; height: 70px"
:src="row[prop]"
:preview-src-list="[row[prop]]"
fit="cover"
preview-teleported
></el-image>
</div>
</template>
<script>
export default {
props: {
row: {
type: Object,
require: true
},
prop: {
type: String,
require: true
},
config: {
type: Object,
require: true
}
},
data() {
return {};
}
};
</script>
<style lang="scss" scoped></style>
主要將我們傳入的文件地址,轉(zhuǎn)化為圖片展示出來。
input組件:
<template>
<div>
<el-input v-model="row[prop]" clearable></el-input>
</div>
</template>
<script>
export default {
props: {
row: {
type: Object,
require: true
},
prop: {
type: String,
require: true
},
config: {
type: Object,
require: true
}
},
data() {
return {};
}
};
</script>
<style lang="scss" scoped></style>
主要將我們傳入的內(nèi)容綁定到input輸入框里面,一般進行編輯操作。
text組件:
<template>
<div>
{{ row[prop] }}
</div>
</template>
<script>
export default {
props: {
row: {
type: Object,
require: true
},
prop: {
type: String,
require: true
},
config: {
type: Object,
require: true
}
},
data() {
return {};
}
};
</script>
<style lang="scss" scoped></style>
直接展示表格內(nèi)容。
最終得到的表格效果:

表格圖片
總結(jié)
以上就是介紹的兩種封裝Table組件的方式。核心都是基于配置文件去進行渲染Table,渲染具體的內(nèi)容可以使用插槽或者動態(tài)組件。
如果項目中需要用到的插槽比較多,推薦使用動態(tài)組件的方式。
更多關(guān)于Vue組件封裝Table的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
vue 動態(tài)設(shè)置瀏覽器標(biāo)題的方法詳解
這篇文章主要為大家介紹了vue動態(tài)設(shè)置瀏覽器標(biāo)題的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2021-12-12
vue 實現(xiàn)模糊檢索并根據(jù)其他字符的首字母順序排列
這篇文章主要介紹了vue 實現(xiàn)模糊檢索,并根據(jù)其他字符的首字母順序排列,本文通過實例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2019-09-09
vue中echarts圖表大小適應(yīng)窗口大小且不需要刷新案例
這篇文章主要介紹了vue中echarts圖表大小適應(yīng)窗口大小且不需要刷新案例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-07-07

