前端使用xlsx.js导入导出excel并展示

因为项目中有需求要展示excel(内容只有一些简单的地址/地区等信息,没有复杂的样式,只是包含了一些合并的表格),所以利用XLSX的读写功能,对读取后的数据进行二次处理并展示。

效果截图在最下边

先上代码(直接从项目中摘抄出一部分,并附上了注释):

//当时项目用的是vue,为了省事只将有用的部分筛选了出来
<template>
  <div class="about">
    <button @click="createBook">生成excel</button>
    <br>
    <input type="file" id="inputFile" @change="fileChange">
    <table id="tableView" style="min-width: 100%; border-collapse:collapse; border: 1px solid;">
      <tr v-for="(item, index) in dataSource" :key="index" style="height: 28px;">
        <template v-for="(sub, subIndex) in item" :key="subIndex">
          <td v-if="sub.rowspan !== 0 && sub.colspan !== 0"
              :rowspan="sub.rowspan || 1" :colspan="sub.colspan || 1"
              style="width: auto; min-width: 120px; padding: 3px 5px; border: 1px solid;">
            {{sub.name}}
          </td>
        </template>
      </tr>
    </table>
  </div>
</template>

<script>
  import {axios} from '@/utils/request'

  const XLSX = require('@/utils/xlsx.full.min')

  export default {
    data() {
      return {
        dataSource: [],
      }
    },
    methods: {
      //获取本地文件
      fileChange() {
        let files = document.getElementById('inputFile').files
        this.fileReader(files[0])
      },
      // //获取网络文件
      // getNetworkFile(url) {
      //   axios({
      //     url,   //文件地址
      //     method: 'get',
      //     responseType: 'blob'
      //   }).then(blobData => {
      //     console.log(blobData)
      //     //将blob转为file类型
      //     let file = new File([blobData], '样例', {type: blobData.type})
      //     this.fileReader(file)
      //   })
      // },

      fileReader(file) {
        let reader = new FileReader()
        //读入file
        reader.readAsBinaryString(file)
        reader.onload = e => {
          let data = e.target.result
          //读取file, 提取数据
          let workbook = XLSX.read(data, {type: 'binary', cellStyles: true})
          console.log(workbook)
          // workbook.SheetNames 是工作表名称的有序列表
          // workbook.Sheets 是一个对象,其键是工作表名称,其值是工作表对象
          this.sheetNames = workbook.SheetNames
          this.sheets = workbook.Sheets
          //默认显示第一个sheet
          this.parsingTable(this.sheets[this.sheetNames[0]])
        }
      },

      //对数据进行处理,实现表格合并展示的功能
      parsingTable(table) {
        let header = []  //表格列
        let keys = Object.keys(table)
        let maxRowIndex = 0  //最大行数
        //!ref工作表范围
        if (table['!ref'] && table['!ref'].includes(':')) {
          let refs = table['!ref'].split(':')
          maxRowIndex = refs[1].replace(/[A-Z]/g, '')
        }
        for (let [i, h] of keys.entries()) {
          //提取key中的英文字母
          let col = h.replace(/[^A-Z]/g, '')
          //单元格是以A-1的形式展示的,所以排除包含!的key
          h.indexOf('!') === -1 && header.indexOf(col) === -1 && header.push(col)
          //如果!ref不存在时,  设置某一列最后一个单元格的索引为最大行数
          if ((!table['!ref'] || !table['!ref'].includes(':')) && header.some(c => table[`${c}${i}`])) {
            maxRowIndex = i > maxRowIndex ? i : maxRowIndex
          }
        }
        header = header.sort((a, b) => a.localeCompare(b))  //按字母顺序排序 [A, B, ..., E, F]
        // console.log(header)
        // console.log(maxRowIndex)

        let dataSource = []   //表格数据
        //excel的行表示为 1, 2, 3, ......, 所以index起始为1
        for (let index = 1; index <= maxRowIndex; index++) {
          let row = []  //行
          //每行的单元格集合, 例: [A1, ..., F1]
          row = header.map(item => {
            let key = `${item}${index}`
            let cell = table[key]
            return {
              key,
              name: cell ? cell.v : '',
              // style: cell ? cell.s : '',   //单元格的样式/主题, 有些不适用
            }
          })
          dataSource.push(row)
        }

        //合并单元格
        if (table['!merges']) {
          for (let item of table['!merges']) {
            //s开始  e结束  c列  r行  (行、列的索引都是从0开始的)
            for (let r = item.s.r; r <= item.e.r; r++) {
              for (let c = item.s.c; c <= item.e.c; c++) {
                // console.log('=======', r, c)
                //查找单元格时需要r+1
                //例:单元格A1的位置是{c: 0, r:0}
                let rowIndex = r + 1
                if (!dataSource[r]) {
                  dataSource.splice(r, 0, header.map(col => ({key: `${col}${rowIndex}`})))
                }
                let cell = dataSource[r].find(a => a.key === `${header[c]}${rowIndex}`)
                cell.rowspan = 0
                cell.colspan = 0
              }
            }


            //合并时保留范围内左上角的单元格
            let start = `${header[item.s.c]}${item.s.r + 1}`
            // let end = `${header[item.e.c]}${item.e.r + 1}`
            // console.log(start)
            let cell = dataSource[item.s.r].find(a => a.key === start)
            cell.rowspan = item.s.r !== item.e.r ? item.e.r - item.s.r + 1 : 1   //纵向合并
            cell.colspan = item.s.c !== item.e.c ? item.e.c - item.s.c + 1 : 1   //横向合并

          }
        }
        console.log(dataSource)

        this.dataSource = dataSource
      },


      createBook() {
        //使用table_to_sheet或table_to_book其中一种方法

        //table_to_sheet的用法
        let worksheet = XLSX.utils.table_to_sheet(document.getElementById('tableView'))
        let workbook = {
          SheetNames: [],
          Sheets: {}
        }
        workbook.SheetNames.push('sheet1')
        worksheet['!cols'] = [{wch: 20}] //设置第一列的列宽
        workbook.Sheets['sheet1'] = worksheet

        //table_to_book的用法
        // let workbook = XLSX.utils.table_to_book(document.getElementById('tableView'));


        let data = XLSX.write(workbook, {
          bookType: 'xlsx', // 要生成的文件类型
          type: 'array'
        })
        let blobData = new Blob([data], {type: 'application/octet-stream'})
        this.downFile(blobData)
      },

      downFile(blobData) {
        if (typeof window.navigator.msSaveBlob !== 'undefined') {
          window.navigator.msSaveBlob(new Blob([blobData]), new Date().getTime() + '.xlsx')
        } else {
          let url = window.URL.createObjectURL(new Blob([blobData]))
          let link = document.createElement('a')
          link.style.display = 'none'
          link.href = url
          link.setAttribute('download', new Date().getTime() + '.xlsx')
          document.body.appendChild(link)
          link.click()
          document.body.removeChild(link)
          window.URL.revokeObjectURL(url)
        }
      }
    },
  }
</script>

本地文件(样式是我自己加的,读取或写入样式需要将cellStyles设置为true):
在这里插入图片描述
页面渲染的table(只实现了表格合并,没有对其他样式进行处理):
在这里插入图片描述
导出后的文件:
在这里插入图片描述

欢迎大家留言讨论!!!

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
好的,以下是一个利用 js-xlsx 实现 Excel 文件导入导出功能的示例: 首先在 HTML 文件中引入 js-xlsx 库: ```html <script src="https://cdn.jsdelivr.net/npm/xlsx/dist/xlsx.full.min.js"></script> ``` 然后在 JavaScript 文件中编写以下代码: ```javascript // 导出 Excel 文件 function exportExcel(data, filename) { const ws = XLSX.utils.json_to_sheet(data); const wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, 'Sheet1'); XLSX.writeFile(wb, `${filename}.xlsx`); } // 导入 Excel 文件 function importExcel(file, callback) { const reader = new FileReader(); reader.readAsArrayBuffer(file); reader.onload = (e) => { const data = new Uint8Array(e.target.result); const workbook = XLSX.read(data, { type: 'array' }); const sheetName = workbook.SheetNames[0]; const worksheet = workbook.Sheets[sheetName]; const result = XLSX.utils.sheet_to_json(worksheet, { header: 1 }); callback(result); }; } ``` 其中,exportExcel 函数用于将数据导出Excel 文件,参数 data 为要导出的数据,filename 为导出的文件名。 importExcel 函数用于导入 Excel 文件,参数 file 为要导入的文件,callback 为导入成功后的回调函数,回调函数的参数 result 为导入的数据。 示例代码中使用了 FileReader 对象读取文件内容,然后使用 js-xlsx 库解析 Excel 文件并将数据转化为 JSON 格式。 使用示例: ```javascript const data = [ { name: '张三', age: 20, gender: '男' }, { name: '李四', age: 22, gender: '女' }, { name: '王五', age: 25, gender: '男' }, ]; exportExcel(data, 'test'); // 导出 Excel 文件,文件名为 test.xlsx const inputElement = document.getElementById('input-file'); inputElement.addEventListener('change', (e) => { const file = e.target.files[0]; importExcel(file, (result) => { console.log(result); // 输出导入的数据 }); }); ``` 在 HTML 文件中添加一个文件选择框: ```html <input type="file" id="input-file"> ``` 用户选择一个 Excel 文件后,调用 importExcel 函数导入数据,并在回调函数中处理导入的数据。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值