工作一年医清,主要職責(zé)是負(fù)責(zé)公司后臺(tái)管理平臺(tái)的開發(fā)與維護(hù)放可。此間面對(duì)各種業(yè)務(wù)需求法褥,通過(guò)面向谷歌編程等常見方式茫叭,積累了一些微不足道的經(jīng)驗(yàn)。
本篇為總結(jié)的第一篇(也許有其他篇)—— table 篇
對(duì)于后臺(tái)管理平臺(tái)來(lái)說(shuō)挖胃,最必不可少的元素就是 table 表格杂靶,幾乎每個(gè)頁(yè)面都涉及到表格的使用,甚至常作為是頁(yè)面的主體部分酱鸭。
因此吗垮,如何維護(hù)這些 table,并且根據(jù)業(yè)務(wù)需求完善不同解決方案凹髓,便是此文所會(huì)表達(dá)的內(nèi)容烁登。
主要技術(shù)棧如題為 vue 全家桶配合 element-ui(其他技術(shù)棧其實(shí)思路是類似的),因此主要還是對(duì) el-table 等的再封裝等蔚舀。element-ui 的文檔已經(jīng)非常通俗易懂饵沧,本文不涉及一些文檔上已有的基本用法。
接下來(lái)我會(huì)模擬一些簡(jiǎn)單的數(shù)據(jù)來(lái)展示一些業(yè)務(wù)問題的解決方案赌躺,其目的在展示思路狼牺,代碼以簡(jiǎn)易為主。
1. 自定義列表項(xiàng)
很多時(shí)候我們需要將后端數(shù)據(jù)作展示優(yōu)化
// mock 數(shù)據(jù)(跳過(guò)直接往下看)
tableData: [
{
id: "12987122",
name1: "王小虎",
name2: "王小虎",
name3: "王小虎",
address1: "上海市普陀區(qū)金沙江路 1518 弄",
address2: "上海市普陀區(qū)金沙江路 1518 弄",
address3: "上海市普陀區(qū)金沙江路 1518 弄",
amount1: "234",
amount2: "3.2",
amount3: 10,
amount4: "4.43",
amount5: 12
},
{
id: "12987123",
name1: "王小虎",
name2: "王小虎",
name3: "王小虎",
address1: "上海市普陀區(qū)金沙江路 1518 弄",
address2: "上海市普陀區(qū)金沙江路 1518 弄",
address3: "上海市普陀區(qū)金沙江路 1518 弄",
amount1: "165",
amount2: "4.43",
amount3: 12,
amount4: "4.43",
amount5: 12
},
{
id: "12987124",
name1: "王小虎",
name2: "王小虎",
name3: "王小虎",
address1: "上海市普陀區(qū)金沙江路 1518 弄",
address2: "上海市普陀區(qū)金沙江路 1518 弄",
address3: "上海市普陀區(qū)金沙江路 1518 弄",
amount1: "324",
amount2: "1.9",
amount3: 9,
amount4: "4.43",
amount5: 12
},
{
id: "12987125",
name1: "王小虎",
name2: "王小虎",
name3: "王小虎",
address1: "上海市普陀區(qū)金沙江路 1518 弄",
address2: "上海市普陀區(qū)金沙江路 1518 弄",
address3: "上海市普陀區(qū)金沙江路 1518 弄",
amount1: "621",
amount2: "2.2",
amount3: 17,
amount4: "4.43",
amount5: 12
},
{
id: "12987126",
name1: "王小虎",
name2: "王小虎",
name3: "王小虎",
address1: "上海市普陀區(qū)金沙江路 1518 弄",
address2: "上海市普陀區(qū)金沙江路 1518 弄",
address3: "上海市普陀區(qū)金沙江路 1518 弄",
amount1: "539",
amount2: "4.1",
amount3: 15,
amount4: "4.43",
amount5: 12
}
],
本次 table 數(shù)據(jù)以上面數(shù)據(jù)模擬后端傳值礼患。我們除了要展示這些字段是钥,還要將后面 5 個(gè) 數(shù)據(jù)作相除或求百分比等,常規(guī)寫法如下(不用細(xì)看):
<el-table
class="table"
:data="tableData"
border
show-summary
highlight-current-row
style="width: 100%"
>
<el-table-column prop="id" label="ID" width="180"></el-table-column>
<el-table-column prop="name1" label="姓名1" width="100"></el-table-column>
<el-table-column prop="name2" label="姓名2" width="100"></el-table-column>
<el-table-column prop="name3" label="姓名3" width="100"></el-table-column>
<el-table-column prop="address1" label="地址1" width="180" show-overflow-tooltip></el-table-column>
<el-table-column prop="address2" label="地址2" width="180" show-overflow-tooltip></el-table-column>
<el-table-column prop="address3" label="地址3" width="180" show-overflow-tooltip></el-table-column>
<el-table-column prop="amount1" sortable label="數(shù)值1"></el-table-column>
<el-table-column prop="amount2" sortable label="數(shù)值2"></el-table-column>
<el-table-column prop="amount3" sortable label="數(shù)值3"></el-table-column>
<el-table-column prop="amount4" sortable label="數(shù)值4"></el-table-column>
<el-table-column prop="amount5" sortable label="數(shù)值5"></el-table-column>
<el-table-column prop="amount6" sortable label="數(shù)值6">
<template slot-scope="scope">
<span>{{toFixedTwo(scope.row.amount1, scope.row.amount2)}}</span>
<span>
</template>
</el-table-column>
<el-table-column prop="amount7" sortable label="數(shù)值7">
<template slot-scope="scope">
<span>{{toFixedTwo(scope.row.amount1, scope.row.amount3)}}</span>
<span>
</template>
</el-table-column>
<el-table-column prop="amount8" sortable label="數(shù)值8">
<template slot-scope="scope">
<span>{{toFixedTwo(scope.row.amount1, scope.row.amount4)}}</span>
<span>
</template>
</el-table-column>
<el-table-column prop="amount9" sortable label="數(shù)值9">
<template slot-scope="scope">
<span>{{toFixedTwo(scope.row.amount1, scope.row.amount5)}}</span>
<span>
</template>
</el-table-column>
<el-table-column prop="amount10" sortable label="數(shù)值10">
<template slot-scope="scope">
<span>{{toPercent(scope.row.amount1, scope.row.amount2)}}</span>
<span>
</template>
</el-table-column>
<el-table-column prop="amount11" sortable label="數(shù)值11">
<template slot-scope="scope">
<span>{{toPercent(scope.row.amount1, scope.row.amount3)}}</span>
<span>
</template>
</el-table-column>
<el-table-column prop="amount12" sortable label="數(shù)值12">
<template slot-scope="scope">
<span>{{toPercent(scope.row.amount1, scope.row.amount4)}}</span>
<span>
</template>
</el-table-column>
<el-table-column prop="amount13" sortable label="數(shù)值13">
<template slot-scope="scope">
<span>{{toPercent(scope.row.amount1, scope.row.amount5)}}</span>
<span>
</template>
</el-table-column>
</el-table>
可以看到缅叠,僅僅是這十來(lái)個(gè)字段悄泥,就讓頁(yè)面顯得非常臃腫,而且很多重復(fù)肤粱,可想而知如果字段增致幾十上百弹囚,展示方式更加繁瑣,開發(fā)維護(hù)不易领曼。
用表驅(qū)動(dòng)編程進(jìn)行優(yōu)化
表驅(qū)動(dòng)法是《代碼大全》里面提到編程方法鸥鹉,適用于多個(gè) if-else 這樣形式的代碼蛮穿,這里自然十分適用。
demo 代碼的目錄結(jié)構(gòu)
tableData.js
將要展示的字段按順序宋舷,以一定參數(shù)形式的數(shù)組結(jié)構(gòu)放在 TABLE_DATA_MAP
對(duì)象內(nèi)绪撵,如目前僅有的 tableDemo 即表示為我們上面代碼的表結(jié)構(gòu)數(shù)組。
/**
* 參數(shù)作用說(shuō)明:
* key: 展示字段
* label: 列頭名稱
* width: 列寬
* sortable: 是否可篩選
* hidden: 隱藏默認(rèn)展示字段
* Dict: 展示用字典
* isFixedTwo: 保留兩位(可配合分子/分母使用)
* isPercent: 百分號(hào)展示(配合分子/分母使用)
* molecule: 分子
* denominator: 分母
**/
export const TABLE_DATA_MAP = {
tableDemo: [
{
key: "name1",
label: "姓名1",
width: 100,
},
{
key: "name2",
label: "姓名2",
width: 100,
},
{
key: "name3",
label: "姓名3",
width: 100,
},
{
key: "address1",
label: "地址1",
width: 180,
},
{
key: "address2",
label: "地址2",
width: 180,
},
{
key: "address3",
label: "地址3",
width: 180,
},
{
key: "amount1",
label: "數(shù)值1",
width: 100,
sortable: true,
},
{
key: "amount2",
label: "數(shù)值2",
width: 100,
sortable: true,
},
{
key: "amount3",
label: "數(shù)值3",
width: 100,
sortable: true,
},
{
key: "amount4",
label: "數(shù)值4",
width: 100,
sortable: true,
},
{
key: "amount5",
label: "數(shù)值5",
width: 100,
sortable: true,
},
{
key: "amount6",
molecule: "amount1",
denominator: "amount2",
label: "數(shù)值6",
width: 100,
sortable: true,
isFixedTwo: true,
hidden: true,
},
{
key: "amount7",
molecule: "amount1",
denominator: "amount3",
label: "數(shù)值7",
width: 100,
sortable: true,
isFixedTwo: true,
hidden: true,
},
{
key: "amount8",
molecule: "amount1",
denominator: "amount4",
label: "數(shù)值8",
width: 100,
sortable: true,
isFixedTwo: true,
hidden: true,
},
{
key: "amount9",
molecule: "amount1",
denominator: "amount5",
label: "數(shù)值9",
width: 100,
sortable: true,
isFixedTwo: true,
hidden: true,
},
{
key: "amount10",
molecule: "amount1",
denominator: "amount2",
label: "數(shù)值10",
width: 100,
sortable: true,
isPercent: true,
hidden: true,
},
{
key: "amount11",
molecule: "amount1",
denominator: "amount3",
label: "數(shù)值11",
width: 100,
sortable: true,
isPercent: true,
hidden: true,
},
{
key: "amount12",
molecule: "amount1",
denominator: "amount4",
label: "數(shù)值12",
width: 100,
sortable: true,
isPercent: true,
hidden: true,
},
{
key: "amount13",
molecule: "amount1",
denominator: "amount5",
label: "數(shù)值13",
width: 100,
sortable: true,
isPercent: true,
hidden: true,
},
]
}
tableColumn.vue
用于對(duì) el-table-colum 的二次封裝祝蝠,配合上面表結(jié)構(gòu)使用(直接看代碼,其中 toFixedTwo幻碱,toPercent 函數(shù)在 mixin 混入)
<template>
<div>
<div v-for="(item, index) in TABLE_DATA_MAP[tableName]" :key="index + item">
<el-table-column
:label="item.label"
:key="index + item"
:min-width="item.width"
:sortable="item.sortable"
:prop="item.key"
show-overflow-tooltip
>
<template slot-scope="scope">
<span v-if="!item.hidden">{{ scope.row[item.key] }}</span>
<span v-if="item.Dict">{{ item.Dict[scope.row[item.key]] }}</span>
<span
v-if="item.isFixedTwo"
>{{toFixedTwo(scope.row[item.molecule], scope.row[item.denominator])}}</span>
<span
v-if="item.isPercent"
>{{toPercent(scope.row[item.molecule], scope.row[item.denominator])}}</span>
</template>
</el-table-column>
</div>
</div>
</template>
<script>
import { TABLE_DATA_MAP } from "@/utils/tableData";
export default {
name: "table-column",
props: {
tableName: String
},
data() {
return {
TABLE_DATA_MAP
};
}
};
</script>
Table.vue
優(yōu)化后的頁(yè)面如下绎狭,與之前相比是不是簡(jiǎn)潔了不少
<template>
<div>
<el-table
class="table"
:data="tableData"
border
show-summary
highlight-current-row
style="width: 100%"
>
<el-table-column prop="id" label="ID" width="120" fixed="left"></el-table-column>
<table-column tableName="tableDemo"></table-column>
</el-table>
</div>
</template>
<script>
export default {
data() {
return {
tableData: [
...
],
};
},
components: {
"table-column": () => import("@/components/tableColumn")
},
methods: {
getSummaries(param) {
...
}
}
};
</script>
除了一些必要參數(shù)(如 key label)外,你可以在 tableData.js 中自定義任何參數(shù)褥傍,配合 tableColumn.vue 使用儡嘶。與此同時(shí),你可以在 tableColumn.vue 上對(duì)一些單獨(dú)字段進(jìn)行特殊處理
// 對(duì) xxx 字段進(jìn)行自定義
<template slot-scope="scope">
<div v-if="item.key === 'xxx'">
<span>{{(scope.row['xxx'] + scope.row['xxx1']+ scope.row['xxx2']).toFixed(2)}}</span>
</div>
</template>
合計(jì)列
此時(shí)如果需求要求合計(jì)值恍风,也能夠通過(guò) TABLE_DATA_MAP
內(nèi)數(shù)據(jù)快速實(shí)現(xiàn)(表驅(qū)動(dòng)法經(jīng)典場(chǎng)景蹦狂,你可以想象不用現(xiàn)在的方法需要幾個(gè) if-else)
<template>
<div>
<el-table
class="table"
:data="tableData"
border
show-summary
:summary-method="getSummaries"
highlight-current-row
style="width: 100%"
>
<el-table-column prop="id" label="ID" width="120" fixed="left"></el-table-column>
<table-column tableName="tableDemo"></table-column>
</el-table>
</div>
</template>
<script>
import { TABLE_DATA_MAP } from "@/utils/tableData";
export default {
data() {
return {
TABLE_DATA_MAP,
tableData: [
...
],
// totalData 模擬 amount 初始合計(jì)值(很可能合計(jì)值非簡(jiǎn)單的疊加,一般由后端傳遞)
totalData: {
amount1: 1883,
amount2: 15.83,
amount3: 63,
amount4: 22.15,
amount5: 60
}
};
},
...
methods: {
getSummaries({ columns }) {
let sums = [];
columns.forEach((column, index) => {
if (column.property === "id") {
sums[index] = "合計(jì)";
return;
} else {
this.TABLE_DATA_MAP.tableDemo.forEach(keyObject => {
if (keyObject.key === column.property) {
if (keyObject.isPercent && keyObject.isPercent === true) {
sums[index] = this.toPercent(
this.totalData[keyObject.molecule],
this.totalData[keyObject.denominator]
);
} else if (
keyObject.isFixedTwo &&
keyObject.isFixedTwo === true
) {
sums[index] = this.toFixedTwo(
this.totalData[keyObject.molecule],
this.totalData[keyObject.denominator]
);
} else {
sums[index] = this.totalData[column.property];
}
}
});
}
});
return sums;
}
}
};
</script>
動(dòng)態(tài)列表配置
對(duì)于一些列表字段較多的 table 頁(yè)面朋贬,實(shí)現(xiàn)列表字段的動(dòng)態(tài)配置的需求就自然而然產(chǎn)生了凯楔。
也是得益于我們的表驅(qū)動(dòng)法,我們能夠很簡(jiǎn)單得做到這一點(diǎn)锦募。
更新的目錄結(jié)構(gòu):
Table.vue
<template>
<div>
<el-button style="margin-bottom:10px;" type="primary" @click="dialogs.configuration.show=true">列表配置</el-button>
<el-table
...
</el-table>
<el-dialog
:title="dialogs.configuration.title"
:visible.sync="dialogs.configuration.show"
:close-on-click-modal="false"
width="700px"
>
<transfer
:model="dialogs.configuration.data"
:tableName="'tableDemo'"
@close="dialogs.configuration.show=false"
@editSuc="editSuc('configuration')"
></transfer>
</el-dialog>
</div>
</template>
<script>
import { TABLE_DATA_MAP } from "@/utils/tableData";
const tableData = [
...
];
export default {
data() {
return {
TABLE_DATA_MAP,
tableData: [],
totalData: {
...
},
dialogs: {
configuration: {
title: "動(dòng)態(tài)列表配置",
data: "",
show: false
}
}
};
},
components: {...},
mounted(){
this.getList()
},
methods: {
getList() {
// 模擬數(shù)據(jù)獲取
setTimeout(() => {
this.tableData = tableData;
}, 1000);
},
getSummaries({ columns }) {
...
},
editSuc(obj) {
this.dialogs[obj].show = false;
this.$message({
message: "提交成功",
type: "success"
});
this.tableData = []
this.getList()
}
}
};
</script>
transfer.vue
<template>
<div>
<el-transfer
filterable
:filter-method="filterMethod"
filter-placeholder="請(qǐng)輸入表頭名"
v-model="value"
:data="data"
></el-transfer>
<el-button type="primary" @click="doSubmit()">提交</el-button>
</div>
</template>
<script>
import { TABLE_DATA_MAP } from "@/utils/tableData";
export default {
props: {
tableName: String
},
data() {
return {
TABLE_DATA_MAP,
data: TABLE_DATA_MAP[this.tableName], // 當(dāng)前頁(yè)默認(rèn)值
value: [], // 現(xiàn)在在 transfer 右測(cè)的值
filterMethod(query, item) {
return item.label.indexOf(query) > -1;
}
};
},
computed: {
currentTableData() {
return this.$store.state.currentTableData;
}
},
methods: {
doSubmit() {
let sData = [];
this.value.map(items => {
this.TABLE_DATA_MAP[this.tableName].forEach(item => {
if (item.key === items) {
sData.push(item);
}
});
});
// 這里如果是實(shí)際項(xiàng)目應(yīng)該會(huì)給后端接口傳值來(lái)保存當(dāng)前用戶該頁(yè)面的設(shè)置
this.$store.commit("SET_TABLE_DATA", {
type: this.tableName,
data: sData
});
this.$emit("editSuc");
}
},
mounted() {
this.value = [];
// 這里如果是實(shí)際項(xiàng)目 currentTableData 應(yīng)該是后端獲取數(shù)據(jù)摆屯,而不是 vuex 獲取
if (this.currentTableData && this.currentTableData[this.tableName]) {
this.currentTableData[this.tableName].forEach(item => {
if (this.TABLE_DATA_MAP[this.tableName].includes(item.key)) {
this.value.push(item.key);
}
});
}
}
};
</script>
tableColumn.vue
<template>
<div>
<div
v-for="(item, index) in ((currentTableData && currentTableData[tableName])? currentTableData[tableName]: TABLE_DATA_MAP[tableName])"
:key="index + item"
>
<el-table-column>
...
</el-table-column>
</div>
</div>
</template>
<script>
import { TABLE_DATA_MAP } from "@/utils/tableData";
export default {
name: "table-column",
props: {
tableName: String
},
data() {
return {
TABLE_DATA_MAP
};
},
computed: {
// currentTableData 實(shí)際工作中應(yīng)該是保存在后端的值
currentTableData() {
return this.$store.state.currentTableData;
}
}
};
</script>
store/index.js
這里使用 vuex 存儲(chǔ) currentTableData(現(xiàn)在所配置的列表字段),如果是實(shí)際工作中糠亩,該數(shù)據(jù)應(yīng)該存儲(chǔ)于后端數(shù)據(jù)(后端保存當(dāng)前用戶對(duì)該頁(yè)面的設(shè)置虐骑,而后在 tableColumn.vue 頁(yè)獲取)
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
currentTableData: {}
},
mutations: {
SET_TABLE_DATA(state, { type, data }) {
state.currentTableData[type] = data
}
},
actions: {
},
modules: {
}
})
思路十分簡(jiǎn)單赎线,本質(zhì)就是在后端保存一份當(dāng)前頁(yè)面用戶表格的私人定制 TABLE_DATA_MAP
文件廷没。
2. 前端導(dǎo)出 table
導(dǎo)出 table 表格是很常見的需求,基本上一些統(tǒng)計(jì)頁(yè)面必備垂寥。
導(dǎo)出有多種方式:
1. 后端實(shí)現(xiàn)數(shù)據(jù)
主要是后端將生成的 table 數(shù)據(jù)流給到前端颠黎,然后前端生成下載鏈接,模擬點(diǎn)擊效果矫废。
downloadFile(data) {
if (!data) {
return
}
let url = window.URL.createObjectURL(new Blob([data]));
let link = document.createElement('a');
link.style.display = 'none';
link.href = url;
link.setAttribute('download', '導(dǎo)出數(shù)據(jù).csv');
document.body.appendChild(link);
link.click()
}
此種方法適用于有分頁(yè)且分頁(yè)量十分大盏缤,還有頁(yè)面數(shù)據(jù)的展示和導(dǎo)出與后端傳遞數(shù)據(jù)(與上面我們需要對(duì)數(shù)據(jù)進(jìn)行百分比等變化的數(shù)據(jù)不同)的情況。
2. 前端導(dǎo)出
需要引入 xlsx 和 file-saver
yarn add slsx file-saver -S
前端實(shí)現(xiàn)導(dǎo)出常見的又有兩種方法:
2.1. 通過(guò)頁(yè)面 Dom 元素獲取數(shù)據(jù)導(dǎo)出
/* eslint-disable */
import FileSaver from 'file-saver'
import XLSX from 'xlsx'
/**
* 導(dǎo)出表格為 excel 格式
* param { Dom } id // document.getElementById('table')
* param { string } fileName // test.xlsx
* param { Boolean } rawBool 純文本解析將不會(huì)解析值
*/
export function exportExcelByDom(id, fileName, rawBool = true) {
/**
* element-ui fixed 是生成兩個(gè) table蓖扑,一個(gè)僅用于固定
* 判斷要導(dǎo)出的節(jié)點(diǎn)中是否有 fixed 的表格
* 如果有唉铜,轉(zhuǎn)換 excel 時(shí)先將該 dom 移除,然后 append 回去
*/
const fix = document.querySelector('.el-table__fixed') || document.querySelector('.el-table__fixed-right');
let wb;
/**
* 從表生成工作簿對(duì)象
*/
if (fix) {
wb = XLSX.utils.table_to_book(document.getElementById(id).removeChild(fix), { raw: rawBool });
document.getElementById(id).appendChild(fix);
} else {
wb = XLSX.utils.table_to_book(document.getElementById(id), { raw: rawBool });
}
/* 獲取二進(jìn)制字符串作為輸出 */
const wbout = XLSX.write(wb, { bookType: 'xlsx', bookSST: true, type: 'array' })
try {
/**
* Blob 對(duì)象表示一個(gè)不可變律杠、原始數(shù)據(jù)的類文件對(duì)象潭流。
* Blob 表示的不一定是JavaScript原生格式的數(shù)據(jù)竞惋。
* File 接口基于Blob,繼承了 blob 的功能并將其擴(kuò)展使其支持用戶系統(tǒng)上的文件灰嫉。
* 返回一個(gè)新創(chuàng)建的 Blob 對(duì)象拆宛,其內(nèi)容由參數(shù)中給定的數(shù)組串聯(lián)組成。
* 設(shè)置導(dǎo)出文件名稱
*/
FileSaver.saveAs(new Blob([wbout], { type: 'application/octet-stream' }), fileName)
} catch (e) {
if (typeof console !== 'undefined') console.log(e, wbout)
}
return wbout
}
此種方法適用于無(wú)分頁(yè)讼撒、導(dǎo)出數(shù)據(jù)即為頁(yè)面看到的樣子的情況浑厚。
2.2 通過(guò) Export2Excel.js
/* eslint-disable */
import FileSaver from 'file-saver'
import XLSX from 'xlsx'
/**
* Export2Excel.js
* param { Array } th // ['姓名']
* param { Array } keyArray // ['name']
* param { Array } jsonData // 處理好的所有數(shù)據(jù)
*/
export function export_json_to_excel(th, keyArray, jsonData, defaultTitle) {
/* original data */
let data = jsonData.map(v => keyArray.map(j => v[j]));
data.unshift(th);
let ws_name = "SheetJS";
let wb = new Workbook(), ws = sheet_from_array_of_arrays(data);
/* add worksheet to workbook */
wb.SheetNames.push(ws_name);
wb.Sheets[ws_name] = ws;
let wbout = XLSX.write(wb, { bookType: 'xlsx', bookSST: false, type: 'binary' });
let title = defaultTitle || '導(dǎo)出數(shù)據(jù)'
FileSaver(new Blob([s2ab(wbout)], { type: "application/octet-stream" }), title + ".xlsx")
};
...
// 其他部分省略
Export2Excel.js 網(wǎng)上有很多版本,大同小異根盒。我對(duì)其 export_json_to_excel
函數(shù)作了封裝钳幅,Export2Excel.js 里面也有通過(guò) DOM 導(dǎo)出的方法,但使用時(shí)會(huì)崩潰炎滞,因此通過(guò) DOM 導(dǎo)出推薦 2.1 方法
又得益于我們之前的 TABLE_DATA_MAP
文件敢艰,2.2 方法導(dǎo)出基本沒有工作量的問題,節(jié)省了很大時(shí)間(相信看到這里册赛,你能夠體會(huì)到表驅(qū)動(dòng)法對(duì) table 的意義)
doExport2Excel() {
const tHeader = ["ID"];
const keyArray = ["id"];
this.TABLE_DATA_MAP.tableDemo.forEach(item => {
tHeader.push(item.label);
keyArray.push(item.key);
});
// 這里 jsonData 應(yīng)該是所要導(dǎo)出的所有數(shù)據(jù)钠导,可讓后端傳值
const jsonData = this.tableData;
jsonData.forEach(list => {
this.TABLE_DATA_MAP.tableDemo.forEach(keyObject => {
if (keyObject.isPercent && keyObject.isPercent === true) {
list[keyObject.key] = this.toPercent(
list[keyObject.molecule],
list[keyObject.denominator]
);
} else if (keyObject.isFixedTwo && keyObject.isFixedTwo === true) {
list[keyObject.key] = this.toFixedTwo(
list[keyObject.molecule],
list[keyObject.denominator]
);
}
});
});
export_json_to_excel(tHeader, keyArray, jsonData, "數(shù)據(jù)導(dǎo)出");
},
這種方法比 2.1 好在:很多時(shí)候?qū)С龅?table 列與展示的是不一致的(如通過(guò)列表配置,展示字段少于導(dǎo)出字段情況)森瘪,我們甚至可以在導(dǎo)出時(shí)對(duì)某些字段作不同于頁(yè)面展示的數(shù)據(jù)處理牡属。
與此同時(shí)其解決了后端導(dǎo)出數(shù)據(jù)會(huì)與展示數(shù)據(jù)不一致的問題,在主動(dòng)性和靈活性上更勝一籌柜砾。
花了快一天時(shí)間寫 demo + 整理湃望,暫時(shí)先寫這么多
不定時(shí)更新。痰驱。证芭。
以上完整代碼看 這里
整理不易,別忘了點(diǎn)個(gè)贊??担映!