exceljs之校验/验证操作的笔记(改个版)

499 阅读3分钟

BALB57CVIGO2%X5IP_HX26P.jpg

让前端,导出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,还是AAAZ,或者AAAAAAAZ,以此类推
    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()
          
  }
     
}

笔记打完收工。。。