一.需求
在做一个报价小项目,需要excel合并相同的危害因素。如下图
二.实现
官网:
1、xlsx-js-style xlsx-js-style | xlsx-js-style homepage
2、xlsx SheetJS 中文网
一、使用第三方插件
1、安装
npm install xlsx-js-style
2、引入
import xlsx from 'xlsx-js-style'
xlsx插件是基础的导出,不可以修改样式,直接xlsx-style插件式修改样式的,所以这里直接用二者合体插件即可
二、页面使用
1、数据源
"data": [
{
"factorName": "X射线;电焊弧光",
"postItem": "放射体检皮肤检查",
"postPrice": 0,
"onDutyItem": "放射体检皮肤检查",
"onDutyPrice": 0,
"departItem": "放射体检皮肤检查",
"departPrice": 0
},
{
"factorName": "X射线;电焊弧光",
"postItem": "放射体检眼科检查",
"postPrice": 0,
"onDutyItem": "放射体检眼科检查",
"onDutyPrice": 0,
"departItem": "放射体检眼科检查",
"departPrice": 0
},
{
"factorName": "X射线;电焊弧光",
"postItem": "肝脾B超(肝脾彩超)",
"postPrice": 48,
"onDutyItem": "甲状腺功能",
"onDutyPrice": 90,
"departItem": "肝脾B超(肝脾彩超)",
"departPrice": 48
}]
2、将数据源转成需要的二维数组
const data = res.map((ele, i) => ({
factorName: ele.factorName,
postItem: ele.postItem,
postPrice: ele.postPrice,
onDutyItem: ele.onDutyItem,
onDutyPrice: ele.onDutyPrice,
departItem: ele.departItem,
departPrice: ele.departPrice,
}))
const body = data.map((x) => [
x.factorName,
x.postItem,
x.postPrice,
x.onDutyItem,
x.onDutyPrice,
x.departItem,
x.departPrice,
])
3、定义表头
// 定义Excel表头
const header = [
[
'危害因素名称',
'入职前必检项目',
'价格',
'在职时必检项目',
'价格',
'离职时必检项目',
'价格',
],
]
4、将定义好的表头添加到 body 中
body.unshift(...header)
5、创建虚拟的 workbook
const workbook = xlsx.utils.book_new()
6、aoa_to_sheet 将二维数组转成 sheet
const sheet = xlsx.utils.aoa_to_sheet(body)
// aoa_to_sheet 是将【一个二维数组】转化成 sheet
// json_to_sheet 是将【由对象组成的数组】转化成sheet
// table_to_sheet 是将【table的dom】直接转成sheet
7、!merges 单元格合并
// 合并单元格的函数
const merges = [
]
function addMerges(startRow, endRow, col) {
if (startRow < endRow) {
merges.push({
s: { r: startRow, c: col },
e: { r: endRow, c: col },
})
}
}
// 动态合并相同内容的单元格的函数
function mergeDynamicCells(colIndex) {
let startRow = 1 // 数据部分从第2行开始
for (let i = 1; i < body.length; i++) {
if (body[i][colIndex] !== body[startRow][colIndex]) {
addMerges(startRow, i - 1, colIndex) // 合并相同内容的单元格
startRow = i // 更新起始行
}
}
addMerges(startRow, body.length - 1, colIndex) // 合并最后一段相同内容
}
// 只对第2列和第5列进行动态合并
mergeDynamicCells(0) // 合并 1 列
sheet['!merges'] = merges // 将合并信息添加到 sheet 中
8、!cols 设置列宽
const cols = [
{ wch: 30 },
{ wch: 30 },
{ wch: 10 },
{ wch: 30 },
{ wch: 10 },
{ wch: 30 },
{ wch: 10 },
]
sheet['!cols'] = cols // 设置列宽
9、!rows 设置行高
const rows = [{ hpx: 30 }, { hpx: 30 }, { hpx: 30 }]
sheet['!rows'] = rows // 行高添加到sheet中
10、样式添加-内容垂直居中
let range = xlsx.utils.decode_range(sheet['!ref']);
let headerStyle = {
font: { sz: 14, name: '宋体', bold: true },
alignment: { vertical: 'center', horizontal: 'center' }
};
let defaultStyle = {
font: { sz: 11, name: '宋体' },
alignment: { wrapText: 1, vertical: 'center', horizontal: 'center' }
// wrapText: 1-------自动换行
};
for (var row = range.s.r; row <= range.e.r; ++row) {
for (let col = range.s.c; col <= range.e.c; ++col) {
let cellAddress = xlsx.utils.encode_cell({ r: row, c: col });
let cell = sheet[cellAddress];
if (cell) {
if (!cell.s) cell.s = {};
// 处理表头
if (cell.v === '隐患排查治理台账') {
cell.s = headerStyle;
} else {
cell.s = defaultStyle;
}
}
}
}
11、向workbook中添加sheet
xlsx.utils.book_append_sheet(workbook, sheet, this.compname || 'Sheet')
12、导出
xlsx.writeFile(workbook, (this.compname || 'Data') + '.xlsx', {type: 'binary',})
三、完整代码
/**
* Excel导出
* **/
const downLoad = () => {
// 列表数据
const res = quotationsData.value;
const data = res.map((ele, i) => ({
factorName: ele.factorName,
postItem: ele.postItem,
postPrice: ele.postPrice,
onDutyItem: ele.onDutyItem,
onDutyPrice: ele.onDutyPrice,
departItem: ele.departItem,
departPrice: ele.departPrice,
}))
const body = data.map((x) => [
x.factorName,
x.postItem,
x.postPrice,
x.onDutyItem,
x.onDutyPrice,
x.departItem,
x.departPrice,
])
// 定义Excel表头
const header = [
[
'危害因素名称',
'入职前必检项目',
'价格',
'在职时必检项目',
'价格',
'离职时必检项目',
'价格',
],
]
body.unshift(...header) // 将定义好的表头添加到 body 中
const sheet = xlsx.utils.aoa_to_sheet(body) // aoa_to_sheet 将二维数组转成 sheet
// 合并单元格的函数
const merges = [
]
function addMerges(startRow, endRow, col) {
if (startRow < endRow) {
merges.push({
s: { r: startRow, c: col },
e: { r: endRow, c: col },
})
}
}
// 动态合并相同内容的单元格的函数
function mergeDynamicCells(colIndex) {
let startRow = 1 // 数据部分从第2行开始
for (let i = 1; i < body.length; i++) {
if (body[i][colIndex] !== body[startRow][colIndex]) {
addMerges(startRow, i - 1, colIndex) // 合并相同内容的单元格
startRow = i // 更新起始行
}
}
addMerges(startRow, body.length - 1, colIndex) // 合并最后一段相同内容
}
// 只对第2列和第5列进行动态合并
mergeDynamicCells(0) // 合并 1 列
sheet['!merges'] = merges // 将合并信息添加到 sheet 中
const cols = [
{ wch: 30 },
{ wch: 30 },
{ wch: 10 },
{ wch: 30 },
{ wch: 10 },
{ wch: 30 },
{ wch: 10 },
]
sheet['!cols'] = cols // 设置列宽
// const rows = [{ hpx: 30 }, { hpx: 30 }, { hpx: 30 }]
// sheet['!rows'] = rows // 设置行高
// 合并居中表格内容
var range = xlsx.utils.decode_range(sheet['!ref'])
for (var R = range.s.r; R <= range.e.r; ++R) {
for (var C = range.s.c; C <= range.e.c; ++C) {
var cell_ref = xlsx.utils.encode_cell({ r: R, c: C })
var cell = sheet[cell_ref]
if (cell) {
if (!cell.s) cell.s = {}
if (cell.v == '隐患排查治理台账') {
cell.s = {
font: {
sz: 14,
name: '宋体',
bold: true,
},
alignment: {
vertical: 'center', // 垂直居中
horizontal: 'left', // 水平居中
},
}
} else {
cell.s = {
font: {
sz: 11,
name: '宋体',
},
alignment: {
wrapText: 1, //自动换行
vertical: 'center', // 垂直居中
horizontal: 'left', // 水平居中
},
}
}
}
}
}
const workbook = xlsx.utils.book_new()
xlsx.utils.book_append_sheet(workbook, sheet, 'Sheet') // 向workbook中添加sheet
xlsx.writeFile(workbook, 'quotations.xlsx', { type: 'binary', }) // 导出 workbook})},
}
参考链接:
【纯前端excel导出】vue2纯前端导出excel,使用xlsx插件,修改样式、合并单元格_前端xlsx插件-优快云博客