让前端,导出excel模板(我也不知道为什么)。。。所以exceljs,就用上了。。
1、基本操作
点这里带你穿越过去 不过多赘述、主要是 并不能满足很多东西。。。
2、遇到的问题。(可以直接看问题,不用看后面的 部分完整代码)
①、根据既定模板遍历生成sheet之后,需要增加新的sheet,文字过多,需要合并单元格等操作。
使用api
中给的mergeCells('A1:E6')
等相关操作
②、获取接口返回的数据绑定给 formulae 之后,下载后打开excel有问题
方法一:使用github中
[`'yourSheet'!$${String.fromCharCode(65)}$1:$${String.fromCharCode(64 + data.length)}$1`]
下载之后打开,mac提示算式被替换,然后表格左上角标蓝,下拉选项不见了。windows中,下拉选项也是不展示的。
之前以为是String.fromCharCode(65)
重复导致,后来使用多个String.fromCharCode(65)
生成AAA2
这种也不行,就放弃了。后来看exceljs
中,formulae
给的数组是['""']
,所以使用'"' + data.join(',') + '"'
进行了一次转换。
上述方法,在wps中,或者windows的Excel中,会导致下拉框太大,可能会卡死,所以换一种实现方式。
方法二:使用动态拼接
将formulae存在隐藏的sheet中,然后关联到excel的select下拉框
转换方法
const joinDropdownlist = (data: any, name: string) => {
const DEFAULT_LENGTH = 26 //Excel默认从A-Z,长度即为26
const multiple = Math.ceil(data?.length / DEFAULT_LENGTH) 看看需要重复几次
const repeatA = 'A'.repeat(multiple > 1 ? multiple - 1 : 0) 根据重复次数确定是A-Z,还是AA到AZ,或者AAAA到AAAZ,以此类推
return data.length ? [`'${name}Sheet'!$${repeatA}${String.fromCharCode(65)}$1:$${String.fromCharCode(64 + data.length)}$1`] : ['""']
}
隐藏sheet操作
// 生成额外sheet存储动态选项
for (const key in this.options) {
if (this.options[key].length) {
const sheet = this.workbook.addWorksheet(`${key}Sheet`, {
properties: {
state: 'veryHidden'
},
state: 'hidden'
})
// sheet.state = 'hidden'
sheet.addRow(this.options[key])
}
}
③、需要给所有的sheet中,不同的列增加校验规则。
使用worksheet.dataValidations.add(列,规则)
实现。
大致问题就这几个,小的东西不做记录。
3、项目里的操作
①、起手式
npm i exceljs -D
项目里
import { ajaxRequest } from './api/ajax'
class ExportExcelTemplate{
// excel的视图区域
private excelViews = [
{
x: 0,
y: 0,
width: 10000,
height: 20000,
firstSheet: 0,
activeTab: 1,
visibility: 'visible'
}
]
private sheetContent = '这里是一些无关紧要但是又需要增加进去的sheet内容'
private sheetTitle = '说明'
// 定义要导出excel中一些 实体内容,格式任意,最后自己能拿出来塞进exceljs就行
private get excelTemplate() {
return [
{
name:'excelName-1',
content:[
{
title: {
header: '静态验证',
key: 'staticValidation',
width: 16
},
// 这里是静态验证的demo
validation: this.validation.staticValidation
},{
title: {
header: '动态验证',
key: 'dynamicValidation',
width: 16
},
// 这里是动态验证的demo
validation: this.dynamicFunction()
}
]
},
{
name:'excelName-2',
content:[
{
title: {
header: '静态验证',
key: 'staticValidation',
width: 16
},
// 这里是静态验证的demo
validation: this.validation.staticValidation
},{
title: {
header: '动态验证',
key: 'dynamicValidation',
width: 16
},
// 这里是动态验证的demo
validation: this.dynamicFunction()
}
]
}
]
}
// 定义静态验证
private validation = {
staticValidation:{
type: 'list',
allowBlank: false,
showErrorMessage: true,
formulae: ['"啥,干啥,你干啥"'],
error: '请选择你要的值'
}
}
// 定义动态验证
private dynamicFunction() {
return {
type: 'list',
allowBlank: false,
showErrorMessage: true,
formulae: [this.dropdownlist(this.listData)],
error: '请选择你要的数据'
}
}
// 获取接口数据
private async getData() {
try{
ajaxRequest().then(res=>{
const { data } = res
this.listData = data.map(item=>item.name)
})
}catch(e){
console.error(e)
}
}
// 动态校验 formulae值 转换处理
public joinDropdownlist = (data: any, name: string) => {
const DEFAULT_LENGTH = 26
const multiple = Math.ceil(data?.length / DEFAULT_LENGTH)
const repeatA = 'A'.repeat(multiple > 1 ? multiple - 1 : 0)
return data.length ? [`'${name}Sheet'!$${repeatA}${String.fromCharCode(65)}$1:$${String.fromCharCode(64 + data.length)}$1`] : ['""']
}
// 导出的实体函数
public async exportTemplate(){
// 所需的动态 select 数据
await this.getData()
const ExcelJS = await import('exceljs')
this.workbook = new ExcelJS.Workbook()
this.workbook.views = this.excelViews
// 多个sheet,使用遍历 excel实体内容去渲染
this.excelTemplate.forEach((item:any)=>{
// 这里 Some Sheet 随意定义,反正后续要覆盖,只是声明一个sheet
const worksheet:any = this.workbook.addWorksheet('Some Sheet')
worksheet.name = item.name
// 给当前sheet添加既定 excel实体内容的名字,即表头
worksheet.columns = item.content.map((val: any) => val.title)
// 增加新的sheet
// 我这里内容挂载在content下,所以这样遍历
// 使用String.fromCharCode(65 + idx)来生成从A到Z的列 数据
// 如果超出26列,可以考虑使用AA到AZ或者类似的方法。不然Z之后,fromCharCode转换后就是 / [ 等符号。
item.content.forEach((val: any, idx)=>{
const columnIndex = String.fromCharCode(65 + idx)
worksheet.dataValidations.add(`${columnIndex}2:${columnIndex}9999`, val.validation)
})
// 调整样式
worksheet._columns.forEach((column: any) => {
column.alignment = {
vertical: 'middle',
horizontal: 'center',
wrapText: true
}
})
// 添加过滤器
worksheet.autoFilter = {
from: {
row: 1,
column: 1
},
to: {
row: 9999,
column: worksheet._columns.length
}
}
})
// 增加 类似于文字说明 sheet
const newWorksheet:any = any = this.workbook.addWorksheet('My Sheet')
newWorksheet.name = this.sheetTitle
// 设置列的宽度
newWorksheet.properties.defaultColWidth = 16
// 合并单元格
newWorksheet.mergeCells('A1:E6')
newWorksheet.getCell('E6').value = this.sheetContent
// 让文字换行
newWorksheet.getCell('E6').alignment = { wrapText: true }
// 生成额外sheet存储动态选项
for (const key in this.options) {
if (this.options[key].length) {
const sheet = this.workbook.addWorksheet(`${key}Sheet`, {
properties: {
state: 'veryHidden'
},
state: 'hidden'
})
// sheet.state = 'hidden'
sheet.addRow(this.options[key])
}
}
// 下载excel操作
const buffer = await this.workbook.xlsx.writeBuffer()
const blob = new Blob([buffer], { type: 'application/xlsx' })
const link = document.createElement('a')
link.href = window.URL.createObjectURL(blob)
link.download = 'excel模板.xlsx'
link.click()
}
}
笔记打完收工。。。