Vue業務組件封裝Table表格示例詳解
前言
這個系列主要是分享自己在工作中常用到的業務組件,以及如何對這些組件進行有效的封裝和封裝的思路。註:都是基於element ui進行二次封裝。
封裝組件的基本方法就是通過props和emit進行父子組件的傳值和通信。利用插槽、組件等去增加組件的可擴展性和復用性。
Table組件介紹
用於展示多條結構類似的數據,可對數據進行排序、篩選、對比或其他自定義操作。table組件常用於後臺管理系統,基本上是後臺管理系統中使用頻率最高的組件瞭,一個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: '上海市普陀區金沙江路 1518 弄' }, { date: '2016-05-04', name: '王小虎', address: '上海市普陀區金沙江路 1517 弄' }, { date: '2016-05-01', name: '王小虎', address: '上海市普陀區金沙江路 1519 弄' }, { date: '2016-05-03', name: '王小虎', address: '上海市普陀區金沙江路 1516 弄' }] } } } </script>
table樣式
根據基本的Table代碼,我們可以知道:
- Table渲染的數據是一個數組,數組的每一項包含瞭每一列的信息,然後綁定到el-table的data屬性裡面。
- el-table-column為Table一行中每列的內容,一行有多少列,就寫多少個el-table-column。
- 每個el-table-column中綁定瞭prop、label屬性,他們分別對應data數據裡所渲染出來的內容和每列的表頭文字,註意prop的值一定要與tableData裡的對象屬性相同。
Table組件如何去封裝
通過分析Table代碼我們可以把el-table-column裡面綁定的屬性抽離出一個配置文件,通過對配置文件的遍歷得到所有el-table-column。
配置文件代碼實現
新建LTable組件
我們在components文件夾下新建一個LTable表示我們封裝的Table組件。基於Table組件的基本代碼,我們寫下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" 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的數據我們在LTable裡獲取,不用父組件傳遞過來。這樣做的好處是:將通過接口獲取table數據統一在LTable管理,減少父組件獲取接口數據然後傳遞給LTable的重復代碼邏輯。相應我們需要傳遞請求數據的接口地址。
配置文件
新建一個配置文件tableConfig.js,導出文件內容,然後再需要用到的頁面引入。
export const tableConfig = { columnList: [ { label: "日期", prop: "date", sortable: true //對表格進行排序 }, { label: "圖片", //文字 prop: "imgSrc", //渲染數據對應的屬性 width: "180" //每列對應寬度 }, { label: "姓名", prop: "name" }, { label: "地址", prop: "address" } ], showIndexColumn: true, //是否顯示table索引 showSelectColumn: true, //是否顯示選擇多行 requestUrl: "api/getData" //接口請求地址 };
頁面內容:
<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封裝就完成瞭,可以看到我們在頁面中的代碼是非常少的,隻有引入瞭組件,然後將配置文件綁定到組件上就可以瞭。
不過目前寫的配置都是非常簡單的,如果遇到復雜的表格內容,我們怎麼辦?
配置插槽
剛剛完成的小案例我們發現圖片是直接顯示瞭地址,那我們想展示圖片怎麼辦,一般表格還會有操作列,我們怎麼展示出來呢?
這種我們不能直接渲染數據,而是需要轉換,比較靈活得到我們想要的的內容就需要用到插槽瞭。
首先我們需要在配置文件增加插槽的選項,我們這裡取名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" } ],
對應的LTable組件裡面的渲染邏輯我們也需要調整,改為有插槽和沒有插槽兩種情況去渲染。表格裡的插槽有些在所有表格裡面都會用到比如操作,這種我們就當做默認插槽,寫在LTabl裡面。
不是每個表格都需要用到插槽就是動態插槽瞭,放在對應的頁面裡。
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"> <!-- 動態插槽 --> <slot v-if="!isDefaultSlot(item.slotName)" :name="item.slotName" :row="scope.row"> </slot> <!-- 默認插槽 --> <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>
頁面裡面動態插槽內容:
<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組件的封裝,我們可以自由靈活的顯示我們表格裡的內容。但同時,我們也發現,當我們LTable組件裡涉及到的插槽越來越多的時候,裡面的代碼也會越來越多。隨著我們的項目越來越復雜,需要的插槽可能有幾十個甚至上百個,使用插槽的方式進行封裝開始顯示出瞭很多問題。我們該如何對這種情況進行優化呢?
動態組件
解決插槽存在的問題
針對上面提出的問題,我從自動化的角度進行瞭思考,放棄瞭大量使用插槽,改用組件代替插槽的形式進行優化。將插槽的類型進行匯總,分別定義不同類型的組件去替換插槽,大大減少瞭由插槽產生的代碼。
代碼實現
首先在配置文件裡面添加瞭type屬性,表示它對應哪個動態組件。還添加瞭cb回調函數,主要處理對數據的格式進行轉化。
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方法,他會遞歸獲取相應文件夾下的對應類型文件。
所以我們還需要在相應文件夾下面創建相應的組件,這裡我是在components文件夾下創建瞭control文件夾,control文件夾下放我們對應需要渲染的組件,這裡我創建瞭四個,function、image、input、text,分別對應內容需要轉化、圖片展示、最基本文字、輸入框。根據具體的業務創建不同的組件即可。
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 },
我們通過動態組件的方式,根據我們要渲染的表格內容去加載不同的組件:
<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>
頁面裡面的內容:
<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>
主要調用配置文件裡的cb,傳入表格內容作為參數,進行我們想要的內容轉化。
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>
主要將我們傳入的文件地址,轉化為圖片展示出來。
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>
主要將我們傳入的內容綁定到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>
直接展示表格內容。
最終得到的表格效果:
表格圖片
總結
以上就是介紹的兩種封裝Table組件的方式。核心都是基於配置文件去進行渲染Table,渲染具體的內容可以使用插槽或者動態組件。
如果項目中需要用到的插槽比較多,推薦使用動態組件的方式。
更多關於Vue組件封裝Table的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- 動態實現element ui的el-table某列數據不同樣式的示例
- vue + element動態多表頭與動態插槽
- vue中的slot-scope及scope.row用法
- vue+elementui實現動態添加行/可編輯的table
- 關於el-table表格組件中插槽scope.row的使用方式