javaScript Excel 导出 - 设置列宽,居中,样式

一、简介

      使用 Lay-Excel插件,原本使用 xlsx.js 实现的,但是后来发现xlsx.js 中样式实现存在bug无法解决,于是改用lay-excel,lay-excel其实也是对xlsx.js 的封装,而本文则是对其进一步封装!!! 代码复制调接口直接可用!!!

二、代码

下载插件

npm install lay-excel

import excel from 'lay-excel'
import { Message } from 'element-ui'
/**
 * Date: 2022-04-08 星期五
 * Time: 17:01
 * Author: Dily_Su
 * Remark:
 *      excel 导出
 *      url 文件下载
 */

/**
 * 导出当前页面Table中的数据
 * @param classOrId table Class or Id (唯一性)
 * @param fileName 文件名
 */
export function exportExcelByClassId(classOrId, fileName) {
  const tableData = excel.tableToJson(document.querySelector(classOrId))
  if (tableData.body.length === 0) {
    return Message.error('表格数据为空,不能导出')
  }
  let datalist = []
  if (Array.isArray(tableData.head[0])) {
    tableData.head.forEach(e => {
      datalist.push(headLinkData(e, tableData.body))
    })
    const temp = datalist.map((e, index) => Object.keys(e[0]).length)
    datalist = datalist[temp.indexOf(Math.max(...temp))]
  } else {
    datalist = headLinkData(tableData.head, tableData.body)
  }
  // 加表头
  const head = {}
  // eslint-disable-next-line no-return-assign
  Object.keys(datalist[datalist.length - 1]).forEach(e => head[e] = e)
  datalist.unshift(head)
  exportExcelByList(datalist, fileName)
}

/**
 * 单 sheet 导出,无标题
 * @param {[object]} dataList 数组,默认sheet名为sheet1
 * @param {string} fileName 文件名
 * @param {[string]} mergeList 合并单元格列表
 * @param {number} contextIndex 正文开始索引,默认:1
 */
export function exportExcelByList(dataList, fileName, mergeList, contextIndex) {
  const index = contextIndex || 1
  const config = {
    extend: {
      '!cols': getColConfig(dataList.slice(index)),
      '!merges': getMergeConfig(mergeList || [])
    }
  }
  dataList = excel.filterExportData(setCellStyleWithOutTitle(dataList, index), Object.keys(dataList[index]))
  excel.exportExcel({ sheet1: dataList }, fileName + '.xlsx', null, config)
}

/**
 * 单 sheet 导出
 * @param {[object]} dataList 数组,默认sheet名为sheet1
 * @param {string} fileName 文件名
 * @param {[string]} mergeList 合并单元格列表(除去标题)
 * @param {number} contextIndex 正文开始索引,默认:1
 */
export function exportExcelByListWithTitle(dataList, fileName, mergeList, contextIndex) {
  const title = {}
  const index = contextIndex || 1
  title[Object.keys(dataList[index])[0]] = fileName
  dataList.unshift(title)
  // 文件标题
  const config = {
    extend: {
      // 合并单元数组
      '!cols': getColConfig(dataList.slice(index)),
      '!merges': getMergeConfig(mergeList ? ['A1:' + excel.numToTitle(Object.keys(dataList[index]).length) + '1'].concat(mergeList) : ['A1:' + excel.numToTitle(Object.keys(dataList[index]).length) + '1'])
    }
  }
  dataList = excel.filterExportData(setCellStyleWithTitle(dataList, index), Object.keys(dataList[index]))
  excel.exportExcel({ sheet1: dataList }, fileName + '.xlsx', null, config)
}

/**
 * 多 sheet 导出
 * @param {object} data  object:key为 sheetName,value为 Data
 * @param {string}fileName 文件名
 */
export function exportExcelByListWithSheets(data, fileName) {
  // skipHeader 用于控制List中的属性名是否生成表头
  const title = {}
  title[Object.keys(data[data.length - 1])[0]] = fileName
  data.unshift(title)
  excel.exportExcel(data, fileName + '.xlsx', '.xlsx')
}

/**
 * 设置单元格样式
 * @param {[object]} dataList 数据
 * @param {number} contextIndex 正文开始索引,默认:1
 * @returns {*}
 */
export function setCellStyleWithTitle(dataList, contextIndex) {
  let dataTitle = dataList.slice(0, 1)
  const dataBody = dataList.slice(1)

  // 样式
  // 设置表标题样式
  const titleConfig = {
    s: {
      font: {
        sz: 20,
        bold: true
      },
      alignment: {
        horizontal: 'center',
        vertical: 'center'
      },
      border: {
        top: { style: 'thin', color: { rgb: 'FF000000' }},
        bottom: { style: 'thin', color: { rgb: 'FF000000' }},
        left: { style: 'thin', color: { rgb: 'FF000000' }},
        right: { style: 'thin', color: { rgb: 'FF000000' }}
      }
    }
  }
  dataTitle = excel.setExportCellStyle(dataTitle, excel.getDefaultRange(dataTitle), titleConfig, null)
  return dataTitle.concat(setCellStyleWithOutTitle(dataBody, contextIndex))
}

/**
 * 设置单元格样式
 * @param {[object]} dataList 数据
 * @param {number} contextIndex 正文开始索引,默认:1
 * @returns {*}
 */
export function setCellStyleWithOutTitle(dataList, contextIndex) {
  let dataHeader
  let dataBody
  // 样式
  // 设置表标题样式
  const headerConfig = {
    s: {
      font: {
        bold: true
      },
      alignment: {
        horizontal: 'center',
        vertical: 'center'
      },
      border: {
        top: { style: 'thin', color: { rgb: 'FF000000' }},
        bottom: { style: 'thin', color: { rgb: 'FF000000' }},
        left: { style: 'thin', color: { rgb: 'FF000000' }},
        right: { style: 'thin', color: { rgb: 'FF000000' }}
      }
    }
  }
  // 设置数据样式
  const bodyConfig = {
    s: {
      alignment: {
        horizontal: 'center',
        vertical: 'center'
      },
      border: {
        top: { style: 'thin', color: { rgb: 'FF000000' }},
        bottom: { style: 'thin', color: { rgb: 'FF000000' }},
        left: { style: 'thin', color: { rgb: 'FF000000' }},
        right: { style: 'thin', color: { rgb: 'FF000000' }}
      }
    }
  }

  if (dataList.length < 2) {
    return excel.setExportCellStyle(dataList, excel.getDefaultRange(dataList), headerConfig, null)
  } else {
    dataHeader = dataList.slice(0, contextIndex)
    dataBody = dataList.slice(contextIndex)
    dataHeader = excel.setExportCellStyle(dataHeader, excel.getDefaultRange(dataHeader), headerConfig, null)
    dataBody = excel.setExportCellStyle(dataBody, excel.getDefaultRange(dataBody), bodyConfig, null)
    return dataHeader.concat(dataBody)
  }
}

/**
 *
 * @param {[string]} rangeList
 * @returns {{extend: {"!merges": type[]}}}
 */
export function getMergeConfig(rangeList) {
  const typeList = rangeList.map(range => range.split(':'))
  return excel.makeMergeConfig(typeList)
}

/**
 *
 * @param dataList 数据
 * @returns {$ObjMap} 自适应行号
 */
export function getColConfig(dataList) {
  const keys = Object.keys(dataList[dataList.length - 1])
  const temp = {}
  keys.forEach((k, index) => {
    temp[excel.numToTitle(index + 1)] = []
    temp[excel.numToTitle(index + 1)].push(gerStringLength(k))

    dataList.forEach(e => {
      temp[excel.numToTitle(index + 1)].push(gerStringLength(e[k]))
    })
  })
  const data = {}
  Object.keys(temp).forEach(e => {
    if (e) {
      data[e] = Math.max(...temp[e]) * 10
    }
  })
  return excel.makeColConfig(data, 80)
}

/**
 * 计算字符串长度
 * @param str
 * @returns {number} 长度
 */
function gerStringLength(str) {
  if (!str) {
    return 10
  } else if (str.toString().charCodeAt(0) > 255) {
    /* 再判断是否为中文*/
    return str.toString().length * 2
  } else {
    return str.toString().length
  }
}

/**
 *
 * @param headList 表头,数组
 * @param dataArray 数据,二维数组
 * @returns [*]
 */
function headLinkData(headList, dataArray) {
  const data = []
  dataArray.forEach(d => {
    const temp = {}
    headList.filter(e => e && e.length > 0).forEach((e, index) => {
      temp[e] = d[index]
    })
    data.push(temp)
  })
  return data
  // return data.filter(e => Object.values(e).every(v => v || v.toString().length > 0))
}

/**
 * 下载文件
 * @param url 路径
 * @param name 文件名
 */
export function downloadFileByUrl(url, name) {
  const link = document.createElement('a')
  // 这里是将url转成blob地址,
  fetch(url)
    .then((res) => res.blob())
    .then((blob) => {
      // 将链接地址字符内容转变成blob地址
      link.href = URL.createObjectURL(blob)
      link.download = name
      document.body.appendChild(link)
      link.click()
    })
}

/**
 * 将Index 转换为 字符
 * @param index index
 * @returns {string} 字符坐标
 */
export function index2Char(index) {
  const base = '0ABCDEFGHIJKLMNOPQRSTUVWXYZ'
  let result = ''
  let n = +index
  if (n > 26) {
    while (n > 25) {
      let nowChar
      if ((n % 26) === 0) {
        nowChar = base.charAt(26)
        n = Math.floor(n / 26) - 1
      } else {
        nowChar = base.charAt(n % 26)
        n = Math.floor(n / 26)
      }
      result = nowChar + result
    }
    result = (base.charAt(n % 26)) + result
  } else {
    result = (base.charAt(n)) + result
  }

  return result
}

/**
 * 将字符横坐标转换为index
 * @param str 字符坐标
 * @returns {number} index
 */
export function char2Index(str) {
  const base = '0ABCDEFGHIJKLMNOPQRSTUVWXYZ'
  if (str.length > 1) {
    return base.indexOf(str.substring(0, 1)) * 26 + base.indexOf(str.substring(1))
  } else {
    return base.indexOf(str)
  }
}

三、官方文档

Lay-Excelhttp://excel.wj2015.com/_book/docs/%E5%BF%AB%E9%80%9F%E4%B8%8A%E6%89%8B.html

你可能感兴趣的:(#,javaScript,#,Vue,javascript,前端,vue)