拿走即用的Excel导出方法封装缺陷修正!

前言

# 用xlsx-style玩转Excel导出------拿走即用的Excel导出方法封装 一文中,我们封装了可以实现多种自定义需求的Excel导出方法。然而,在最近的需求开发中,发现此方法在自定义单元格颜色方面有缺陷,故重新修改记录一下。

缺陷

原方法,只能整体定义表头区域样式、内容区域样式,颗粒度未到达每一个单元格。

也就是说,通过原方法定义后,表头区域所有单元格的样式是一样的,内容区域所有单元格的样式也是一样的。

这就不能满足不同单元格展示不同样式的需求。

改进

加入setCellStyle回调函数。

通过setCellStyle函数获取单元格信息,并根据需要处理单元格样式逻辑。

js 复制代码
/** 
  * 配置单元格样式
  * @param { 单元格字段名 } key
  * @param { 单元格内容信息 } info
  * @param { 表头/内容区域区分 } type 
*/ 
  function setCellStyle(key, info, type) { 
    if(条件判断) {
      return {
      }
    }
    return {
        border: {top: {style: 'thin'},bottom: {style: 'thin'},left: {style: 'thin'},right: {style: 'thin'},},
        font: { name: '宋体', sz: 11, italic: false, underline: false },
        alignment: { vertical: 'center', horizontal: 'left',},
        fill: { fgColor: { rgb: 'FFFFFF' } },
    }
  
  }

1.表头

js 复制代码
 // 处理sheet表头
  const _header = data.header.map((item, i) =>
      Object.assign({}, {
        key: item.dataIndex,
        title: item.title,
        // 定位单元格
        position: getCharCol(i) + 1,
        // 设置表头样式
        s: setCellStyle ? setCellStyle(key, item, 'header') : defaultCellStyle.headerStyle,
      })
    ).reduce((prev, next) =>
      Object.assign({}, prev, {
        [next.position]: { v: next.title, key: next.key, s: next.s },
      }), {}
    )
 

2.内容

js 复制代码
 data.dataSource.forEach((item, i) => {
    data.header.forEach((obj, index) => {
        const key = getCharCol(index) + (i + 2)
        const key_t = obj.dataIndex
        _data[key] = {
          v: item[key_t],
          s: setCellStyle? setCellStyle(key_t, item,'content') : defaultCellStyle.dataStyle,
        }
      })
    })

完整代码

js 复制代码
import XLSX from 'xlsx-style'

// 默认工作簿配置

const defaultWorkBook = {
  bookType: 'xlsx',
  bookSST: false,
  type: 'binary',

}

// 默认样式配置

const borderAll = { 
  top: {
    style: 'thin',
  },
  bottom: {
    style: 'thin',
  },
  left: {
    style: 'thin',
  },
  right: {
    style: 'thin',
  },
}

const defaultCellStyle = {
  // 表头区域样式配置
  headerStyle: { 
    border: borderAll,
    font: { name: '宋体', sz: 11, italic: false, underline: false, bold: true },
    alignment: { vertical: 'center', horizontal: 'center' },
    fill: { fgColor: { rgb: 'FFFFFF' } },
  },
  // 内容区域样式配置
  dataStyle: { 
    border: borderAll,
    font: { name: '宋体', sz: 11, italic: false, underline: false },
    alignment: { vertical: 'center', horizontal: 'left', wrapText: true },
    fill: { fgColor: { rgb: 'FFFFFF' } },
  },
}

function exportExcel(exportData, fileName = '未命名',  setCellStyle,  workBookConfig = defaultWorkBook) {

  if (!(exportData && exportData.length)) {
    return
  }
  
  // 定义工作簿对象
  const wb = { SheetNames: [], Sheets: {} }

  exportData.forEach((data, index) => {
  
    // 处理sheet表头
    const _header = data.header.map((item, i) =>
      Object.assign({}, {
        key: item.dataIndex,
        title: item.title,
        // 定位单元格
        position: getCharCol(i) + 1, 
        // 设置表头样式
        s: setCellStyle ? setCellStyle(key, item, 'header') : defaultCellStyle.headerStyle,
      })
    ).reduce((prev, next) =>
      Object.assign({}, prev, {
        [next.position]: { v: next.title, key: next.key, s: next.s },
      }), {}
    )

    // 处理sheet内容
    const _data = {}
    data.dataSource.forEach((item, i) => {
      data.header.forEach((obj, index) => {
        const key = getCharCol(index) + (i + 2)
        const key_t = obj.dataIndex
        _data[key] = {
          v: item[key_t],
           s: setCellStyle? setCellStyle(key_t, item, 'content') : defaultCellStyle.dataStyle,
        }
      })
    })

    const output = Object.assign({}, _header, _data)
    const outputPos = Object.keys(output)


    // 设置单元格宽度
    const colWidth = data.header.map(item => { return { wpx: item.width || 80 } })

    const merges = data.workSheetConfig && data.workSheetConfig.merges

    const freeze = data.workSheetConfig && data.workSheetConfig.freeze

    // 处理sheet名
    
    wb.SheetNames[index] = data.sheetName ? data.sheetName : 'Sheet' + (index + 1)
    
    // 处理sheet数据
    
    wb.Sheets[wb.SheetNames[index]] = Object.assign({},
      output, // 导出的内容
      {
        '!ref': `${outputPos[0]}:${outputPos[outputPos.length - 1]}`,
        '!cols': [...colWidth],
        '!merges': merges ? [...merges] : undefined,
        '!freeze': freeze ? [...freeze] : undefined,
      }
    )
  })
  
  // 转成二进制对象
  const tmpDown = new Blob(
    [s2ab(XLSX.write(wb, workBookConfig))],
    { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }
  )
  
  // 下载表格
  downExcel(tmpDown, `${fileName + '.'}${workBookConfig.bookType === 'biff2' ? 'xls' : workBookConfig.bookType}`)
}

/**
 * 生成ASCll值 从A开始
 * @param {*} n
 */
function getCharCol(n) {
  if (n > 25) {
    let s = ''
    let m = 0
    while (n > 0) {
      m = n % 26 + 1
      s = String.fromCharCode(m + 64) + s
      n = (n - m) / 26
    }
    return s
  }
  return String.fromCharCode(65 + n)
}

// 字符串转字符流---转化为二进制的数据流
function s2ab(s) {
  if (typeof ArrayBuffer !== 'undefined') {
    const buf = new ArrayBuffer(s.length)
    const view = new Uint8Array(buf)
    for (let i = 0; i !== s.length; ++i) { view[i] = s.charCodeAt(i) & 0xff }
    return buf
  } else {
    const buf = new Array(s.length)
    for (let i = 0; i !== s.length; ++i) { buf[i] = s.charCodeAt(i) & 0xff }
    return buf
  }
}

function downExcel(obj, fileName) {
  const a_node = document.createElement('a')
  a_node.download = fileName

  // 兼容ie
  if ('msSaveOrOpenBlob' in navigator) {
    window.navigator.msSaveOrOpenBlob(obj, fileName)
  } else {
    // 新的对象URL指向执行的File对象或者是Blob对象.
    a_node.href = URL.createObjectURL(obj)
  }
  a_node.click()
  setTimeout(() => {
    URL.revokeObjectURL(obj)
  }, 100)
}

export {
  exportExcel,
}
相关推荐
afabama2 分钟前
nvm 安装某个版本的node,缺少npm包
前端·npm·node.js
小宋102130 分钟前
实现Excel文件和其他文件导出为压缩包,并导入
java·javascript·excel·etl
码喽哈哈哈30 分钟前
day01
前端·javascript·html
XT462542 分钟前
解决 npm install 卡住不动或执行失败
前端·npm·node.js
前端小魔女1 小时前
Rust赋能前端: 纯血前端将 Table 导出 Excel
前端
mubeibeinv1 小时前
分页/列表分页
java·前端·javascript
林太白1 小时前
js属性-IntersectionObserver
前端·javascript
爱吃羊的老虎1 小时前
【WEB开发.js】getElementById :通过元素id属性获取HTML元素
前端·javascript·html
lucifer3111 小时前
未集成Jenkins、Kubernetes 等自动化部署工具的解决方案
前端
妙哉7362 小时前
零基础学安全--HTML
前端·安全·html