js解析excel

在平常開發中,遇到批量導入的狀況,一般是將文件上傳至後端來解析excel文件流。這種作法會佔用必定的帶寬和後端性能。如今,JS也能夠解析excel啦。後端

經過使用xlsx庫來解析excel。兼容性方面,支持IE10及以上。在這裏我寫了一個小工具供你們參考。該工具的用途主要是整理xlsx庫解析出來的數據。讓數據更容易使用。工具中暴露出兩個方法:readXlsx和downloadXlsx。數組

readXlsx用於解析上傳的xlsx模板,downloadXlsx用於導出模板。bash

import Xlsx from 'xlsx'

const letters = [
  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
  'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
]

export async function readXlsx(file) {
  if (file) {
    const metaData = await readFile(file)
    const xlsx = Xlsx.read(metaData, {type: 'binary'})
    const data = createArray(xlsx)
    return getData(data, xlsx)
  }
  return {}
}

export async function downloadXlsx(filename, obj) {
  const wb = new WorkBook(obj)
  Xlsx.writeFile(wb, filename)
}

class WorkBook {
  constructor(data) {
    this.SheetNames = Object.keys(data)
    this.Sheets = {}
    for (const name of this.SheetNames) {
      const sheet = {
        [name]: setData(data[name])
      }
      Object.assign(this.Sheets, sheet)
    }
  }
}

function readFile(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader()
    reader.readAsBinaryString(file)
    reader.onload = (e) => {
      resolve(e.target.result)
    }
  })
}

function createArray({SheetNames, Sheets}) {
  const result = {}
  for (const name of SheetNames) {
    const arr = []
    const ref = Sheets[name]['!ref']
    let [x, y] = getRange(ref)
    for (let i = 0; i < y; i++) {
      const tp = []
      for (let j = 0; j < x; j++) {
        tp.push(undefined)
      }
      arr.push(tp)
    }
    Object.assign(result, {[name]: arr})
  }
  return result
}

function getRange(ref) {
  const boundary = ref.split(':')[1]
  const a1 = boundary.split(/[0-9]+/)[0]
  const a2 = boundary.split(/[A-Z]+/)[1]
  return [getNumber(a1), a2 * 1]
}

function getNumber(letter) {
  const arr = letter.split('')
  let result = 0
  for (let i = 0; i < arr.length; i++) {
    result += (letters.indexOf(arr[i]) + 1) * Math.pow(26, arr.length - i - 1)
  }
  return result
}

function getLetter(num) {
  num *= 1
  const t = (num - 1).toString('26')
  const arr = t.split('')
  let result = ''
  for (let i in arr) {
    i *= 1
    const n = parseInt(arr[i], 26) * 1
    result += letters[i !== arr.length - 1 ? n - 1 : n]
  }
  return result
}

function getData(data, {SheetNames, Sheets}) {
  for (const name of SheetNames) {
    const copySheet = JSON.parse(JSON.stringify(Sheets[name]))
    delete copySheet['!margins']
    delete copySheet['!ref']
    const keys = Object.keys(copySheet)
    for (const key of keys) {
      const a1 = key.split(/[0-9]+/)[0]
      const a2 = key.split(/[A-Z]+/)[1]
      const point = {x: getNumber(a1), y: a2 * 1}
      data[name][point.y - 1][point.x - 1] = copySheet[key].v
    }
  }
  return data
}

function setData(data = []) {
  const result = {'!ref': ''}
  let width, height = data.length, start
  for (let i in data) {
    i *= 1
    if (width) {
      if (data[i].length > width) {
        width = data[i].length
      }
    } else {
      width = data[i].length
    }

    for (let j in data[i]) {
      j *= 1
      const v = data[i][j]
      const k = getLetter(j + 1) + (i + 1)
      if (v) {
        result[k] = {v, t: 's'}

        if (!start) {
          start = k
        }
      }
    }
  }
  if (width && height && start) {
    result['!ref'] = `${start}:${getLetter(width) + height}`
  }
  return result
}
複製代碼

首先引入該工具:async

import {readXlsx, downloadXlsx} from './excelUtil'
複製代碼

Import Example:工具

const file = this.$refs['file-container'].files[0]
const data = await readXlsx(file)
console.log(data)
複製代碼

上傳的xlsx被解析成爲了一個二維數組


Export Example:性能

downloadXlsx('hello.xlsx',{"asd": [['帳號', '密碼', '性別', '姓名', '暱稱', '生日', '興趣愛好']]})
複製代碼

導出的模板文件: hello.xlsx

喜歡該文章的話請點擊「關注」喲ui

相關文章
相關標籤/搜索