前端纯JS实现Excel文件导入与导出功能详解

作者:闭包旅人时间:2026-10-25 11:50:33浏览:457

本文详细讲解如何在纯前端环境下使用JavaScript实现Excel文件的导入与导出。通过引入xlsx库,利用FileReader读取二进制数据,结合XLSX.read和sheet_to_json等方法解析文件,以及通过json_to_sheet和book_append_sheet生成并下载Excel文件,无需后端接口支持即可完成数据交互。

一、需求场景描述

文件导入导出是开发中极为常见的需求,其中Excel格式的应用尤为广泛。在实际项目中,这类功能通常通过调用后端接口来完成,即将文件处理逻辑交由服务器处理。然而,在某些特定场景下,由前端直接实现导入导出功能可能是更优的技术选型。

1.此时前端上传解析excel文件可能更合适

例如,当用户需要填写一个标准的Excel模板时,上传后若能在前端预览并直接在线修改,随后选择下载或提交至服务端,体验会更为流畅。特别是当模板数据量较小(如团队成员列表)时,通过文件流传输整个文件可能效率低下,相比之下,前端解析出具体数据行后直接提交JSON数据,既节省带宽又提升响应速度。

因此,在此类场景下,核心需求转化为前端需要具备上传文件并解析Excel内容的能力。

2.此时前端下载excel文件可能优雅一些

如果系统支持用户动态调整筛选条件,且这些变更是临时的、未实时同步至服务器的,服务器端无法直接提供基于最新筛选结果的文件。此时,由前端主导生成并下载Excel文件显得更为合理。虽然也可以先将最终结果同步至服务器再由服务器提供下载,但前端直出能减少网络往返和服务器负载。

针对此类场景,前端需要实现数据的过滤与解析,并直接生成Excel文件供用户下载。

实践效果图如下:

一、需求场景描述

二、实现思路分析

1.导入excel文件实现思路分析

  • 首先,利用HTML原生的文件上传标签(如type为file的input)或UI组件库(如el-upload)从本地获取用户选择的文件。
  • 其次,使用FileReader API将获取到的文件读取为二进制字符串或ArrayBuffer,以便后续处理。
  • 接着,调用xlsx库提供的XLSX.read()方法,将上一步得到的二进制数据转换为Excel的工作簿对象(workbook,简称wb)。
  • 然后,利用XLSX.utils.sheet_to_json()方法,从工作簿中提取第一个工作表(Sheets)的数据,并将其转换为JSON格式对象。
  • 最后,由于从Excel直接提取的数据往往缺乏明确的字段名或字段名不符合前端展示要求,我们需要根据预设的列字段名,对JSON数据进行重组,生成符合业务需求的数组对象。

这一步至关重要,因为我们需要在页面表格中渲染出结构清晰、字段名规范的数据,而原始Excel数据可能不具备这一特性。

2.导出excel文件实现思路分析

  • 首先,调用xlsx库的XLSX.utils.book_new()方法,创建一个新的Excel工作簿对象(wb)。
  • 其次,为了在Excel文件中显示表头,需将表头数据通过数组的unshift()方法插入到数据数组的第一行。
  • 接着,使用XLSX.utils.json_to_sheet()方法,将包含表头和数据的JSON数组转换为Excel的工作表对象(ws)。
  • 然后,通过自定义的json_to_array(key, data)函数,结合指定的字段名key和数据记录data,生成用于计算列宽的数组结构。
  • 随后,调用auto_width()函数,对工作表ws和新生成的数组进行遍历,自动计算并设置各列(col)的宽度,以确保导出文件的可读性。
  • 最后,通过XLSX.utils.book_append_sheet()将工作表添加到工作簿中,并调用XLSX.writeFile()生成实际的Excel文件,触发浏览器下载。

三、关键代码

1. exportExcel.js 导出excel文件

/* eslint-disable */
/* 导出excel文件 */

/**
 * 导出excel文件实现思路分析
 *
 * 1.通过XLSX插件的 XLSX.utils.book_new()方法,创建excel工作蒲对象wb。
 * 2.按需插入第一行数据,通过数组的unshift()方法。
 * 3.通过XLSX.utils.json_to_sheet(),创建excel表格对象ws。
 * 4.通过json_to_array(key,data),结合自定义的字段名key,和数据记录data,生成新数组。
 * 5.通过auto_width(),对ws和新生成的数组,自动计算各列col宽。
 * 6.通过XLSX.utils.book_append_sheet(),生成实际excel工作蒲,并使用XLSX.writeFile()生成excel文件。
 */

import XLSX from 'xlsx'

// 自动计算col列宽
function auto_width (ws, data) {
  /*set worksheet max width per col*/
  const colWidth = data.map(row => row.map(val => {
    /*if null/undefined*/
    if (val == null) {
      return { 'wch': 10 }
    }
    /*if chinese*/
    else if (val.toString().charCodeAt(0) > 255) {
      return { 'wch': val.toString().length * 2 }
    } else {
      return { 'wch': val.toString().length }
    }
  }))
  /*start in the first row*/
  let result = colWidth[0]
  for (let i = 1; i < colWidth.length; i++) {
    for (let j = 0; j < colWidth[i].length; j++) {
      if (result[j]['wch'] < colWidth[i][j]['wch']) {
        result[j]['wch'] = colWidth[i][j]['wch']
      }
    }
  }
  ws['!cols'] = result
}

// 将json数据转换成数组
function json_to_array (key, jsonData) {
  return jsonData.map(v => key.map(j => {
    return v[j]
  }))
}

/**
 * @param header Object,表头
 * @param data Array,表体数据
 * @param key Array,字段名
 * @param title String,标题(会居中显示),即excel表格第一行
 * @param filename String,文件名
 * @param autoWidth Boolean,是否自动根据key自定义列宽度
 */
export const exportJsonToExcel = ({
  header,
  data,
  key,
  title,
  filename,
  autoWidth
}) => {
  const wb = XLSX.utils.book_new()
  if (header) {
    data.unshift(header)
  }
  if (title) {
    data.unshift(title)
  }
  const ws = XLSX.utils.json_to_sheet(data, {
    header: key,
    skipHeader: true
  })
  if (autoWidth) {
    const arr = json_to_array(key, data)
    auto_width(ws, arr)
  }
  XLSX.utils.book_append_sheet(wb, ws, filename)
  XLSX.writeFile(wb, filename + '.xlsx')
}
export default {
  exportJsonToExcel
}

2. importExcel.js 导入excel文件

/* eslint-disable */
/* 导入excel文件 */

/**
 * 导入excel文件实现思路分析
 *
 * 1.使用html支持上传标签从本地获取文件,例如type为file的input,el-upload等。
 * 2.利用FileReader将文件读取为二进制字符串。
 * 3.使用XLSX插件的XLSX.read()方法,将二进制字符串转换成excel文件的工作蒲对象workbook(简写成wb)。
 * 4.通过XLSX.utils.sheet_to_json()方法,从wb中获取第一张 Sheets表格数据并将其转换为json数据。
 * 5.重组json数据生成数组,即是根据自己的定义的列字段名,重新组成符合自己需求的json数据。因为从excel中提取的数据是没有字段名或字段名不符合要求的,
 * 而我们需要渲染在页面表格中又确实需要合适的字段名。
 */


/**
 * @param file 文件流
 * @param tableTemplate 要导入的表格模板,一个数组,如:
 * tableTemplate: ['userCode', 'userName', 'department', 'major', 'position'],其中的值
 * 为表格的字段名,注意字段的顺序应与实际的导入excel一致。
 */
export default function importExcel (file, tableTemplate) {
  return new Promise((resolve, reject) => {
    let f = file.raw // 获取文件内容
    // 通过DOM取文件数据
    let rABS = false // 是否将文件读取为二进制字符串
    let reader = new FileReader()
    FileReader.prototype.readAsBinaryString = function (f) {
      let binary = ''
      let rABS = false // 是否将文件读取为二进制字符串
      let wb // 读取完成的数据
      let outdata
      let reader = new FileReader()
      reader.onload = function (e) {
        let bytes = new Uint8Array(reader.result)
        let length = bytes.byteLength
        for (let i = 0; i < length; i++) {
          binary += String.fromCharCode(bytes[i])
        }
        let XLSX = require('xlsx')
        if (rABS) {
          wb = XLSX.read(btoa(binary), { // 手动转化
            type: 'base64'
          })
        } else {
          wb = XLSX.read(binary, {
            type: 'binary'
          })
        }
        outdata = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]) // outdata就是表格中的值

        let arr = []
        // 下面是数据解析提取逻辑
        if (tableTemplate.length > 0) {
          let tempArr = Object.keys(outdata[0])
          let tempArrNew = []
          for (let i in tempArr) {
            for (let k in tableTemplate) {
              if (i === k) {
                tempArrNew.push({fieldE: tableTemplate[k], fieldC: tempArr[i]})
              }
            }
          }

          tempArr = tempArrNew
          outdata.map(item => {
            let obj = {}
            tempArr.map(temp2 => {
              obj[temp2.fieldE] = item[temp2.fieldC]
            })
            arr.push(obj)
          })
        }

        resolve(arr)
      }
      reader.readAsArrayBuffer(f)
    }

    if (rABS) {
      reader.readAsArrayBuffer(f)
    } else {
      reader.readAsBinaryString(f)
    }
  })
}

四、使用示例

1.使用示例一:上传解析excel

关键 html 代码部分

<el-upload
        action=""
        id="upload-excel"
        :on-change="handleChange"
        :show-file-list="false"
        accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel"
        :auto-upload="false">
</el-upload>

<el-table
        class="cn-table-th-bg"
        size="small"
        :data="tableData"
        border
        style="width: 100%">
    <el-table-column type="index" label="序号" width="50" align="center"></el-table-column>
    <el-table-column prop="userSource" label="来源" align="center"></el-table-column>
    <el-table-column prop="userCode" label="工号" align="center"></el-table-column>
    <el-table-column prop="userName" label="姓名" align="center"></el-table-column>
    <el-table-column prop="department" label="部门" align="center"></el-table-column>
    <el-table-column prop="major" label="专业" align="center"></el-table-column>
    <el-table-column prop="position" label="职务/职称" align="center"></el-table-column>
    <el-table-column label="操作" align="center" width="250">
        <template slot-scope="scope">
            <el-button @click="clickDelete(scope.row)" size="mini">删除</el-button>
            <el-button @click="moveUp(tableData,scope.$index)" size="mini" class="up-button">上移</el-button>
            <el-button @click="moveDown(tableData,scope.$index)" size="mini" class="down-button">下移</el-button>
        </template>
    </el-table-column>
</el-table>

// 关键 js 代码部分

import importExcel from '@/utils/excel/importExcel'

handleChange (file, fileList) {
    tableField: ['userCode', 'userName', 'department', 'major', 'position'],
    importExcel(file, tableField).then(res => {
       this.tableData = res
   })
}

2.使用示例二:下载excel文件

关键 js 代码

import { exportJsonToExcel } from '@/utils/excel/exportExcel'

clickDownload () {
        const tableField = ['userCode', 'userName', 'department', 'major', 'position'],
            tableHeader = {userCode: '工号', userName: '姓名', department: '部门', major: '专业', position: '职位/职称'},
            tableTitle = '导出表格',
            templateData = [
              {'userCode': 'N1001', 'userName': '张三', 'department': '综合管理部', 'major': '计算机科学与技术', 'position': '项目经理'}
            ],
            obj = {
              header: tableHeader,
              data: templateData,
              key: tableField,
              title: '',
              filename: '团队成员导入模板',
              autoWidth: true
           }
        exportJsonToExcel(obj)
},

到此这篇关于JavaScript实现excel文件导入导出的文章就介绍到这了,更多相关JS文件导入导出内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!

作者最新文章