React如何接收excel文件下载导出功能封装

2022-09-15 11:15:58

目录React接收excel文件下载导出功能封装react导出excel文件的几种方式1.原生js导出(带样式)2.使用xlsx导出(此方法导出的excel文件无样式,但导出的文件格式是xlsx格式...

目录
React接收excel文件下载导出功能封装
react导出excel文件的几种方式
1.原生js导出 (带样式)
2.使用xlsx导出(此方法导出的excel文件无样式,但导出的文件格式是 xlsx格式) 
3.使用 js-export-excel (可以导出多张sheet表)
4.第四种 使用react-html-table-to-excel   不推荐使用

React接收excel文件下载导出功能封装

因为最近项目又需求要导出excel,所以封装了这部分的功能,对fetch的封装做了修改,使之后的调用导出功能更为方便

首先这个项目请求是对fetch进行过封装的 ,如果对fetch有了解的话,我们知道fetch种response返回的是一个实现了Body接口的对象, 所以可以使用Body接口中的方法 json()处理json,blob ()处理成blob文件对象 方法, 所以要先对封装的请求方法做如下修改

export default function request(url, option,noToken = false,type = 'json') { 
//这是封装request方法 noToken判断是否写代token type用来区别 json/blob 这里我们需要下载文件所以传入blob
 ...
 .then(response => {
     if (newOptions.method === 'DELETE' || response.status === 204) {
      return response.text();
     }
     if(type == 'blob') {
     return response.blob(); //处理成blob文件类型
     }
     return response.json();
    })
  .then(response => {
    if(type == 'blob') {
    return URL.createObjectURL(response); //使用URL.createObjectURL将blob放入一个object'
    ...
    }
   }
 }
}

上面我们通过一个参数,将blob文件处理成url

export async function exportExcel(params) {
 return request(`/api/xxxxx/${params}`,{method: 'GET'} ,false ,'blob' );
} 

上面就是我们导出文件的请求接口,获得的是一个url,然后我们在effect中接受url

* exportExcel({payload}, {call,put}) {
 try {
  const url = yield call(exportExcel, payload); //收到一个url
  let link = document.createElement('a') //创建一个a标签
  link.style.display = 'none' //不显示
  link.href = url //将地址填入
  link.setAttribute('download', '表格.xlsx') //设置下载属性,取个文件名
  document.body.appendChild(link) //添加到页面上
  link.click() //点击触发下载
 } catch (e) {
 }
},

到这里就是实现了文件的导出,基本原理就是将接受的文件处理成url,用a标签触发下载

其实本来到这里就应该结束了,但是作为一个有原则的程序员, 反复添加a标签显示让我们觉得很不规范, 所以我们来改写成一直复用一个a标签来下载,动态修改url\\现在BasicLayout里加个a标签,因为这个是登陆都最先加载的,保证每个模块都能使用

 <a 
 style={{display: 'none'}}
 ref={(link)=> {this.props.dispatch({type: 'global/saveLink', payload: link})}} //这个是用来讲a标签的ref存到redux里,随时可以调用
 ></a>

**然后我们在modes/global里写两个reducer** 

 reducers: {
  saveLink(state, { payload }) {
  //保存a标签
   return {
    ...state,
    link: payload,
   }
  },
  exportFile(state, { payload }) {
  //设置a标签的地址并触发点击下载
   state.link.href = payload.url
   state.link.setAttribute('download',payload.name)
   state.link.click()
   return {
    ...state,
   };
  },
}

然后我们在普通的模块中effect调用时只需要这么写

* exportExcel({payload}, {call,put}) {
 try {
  const url = yield call(exportExcel, payload); //收到一个url
 yield put({type: 'global/exportFile',payload: {url,name: `表格.xlsx`}}) //设置地址并触发下载
 } catch (e) {
 }
},

这样写方便了很多 ,其实最好的方式是将这部分代码封装到一个组件中,单独调用,这里就不演示了,写法差不多 

react导出excel文件的几种方式

一共总结了四种方法  前两种适用范围比较广泛 可以适用导出多级表头合并等,第三种方法导出的文件比较中规中矩,但是支持导出多张sheet表。第四种方法导出不推荐使用

1.原生js导出 (带样式)

       

/**
* 原生JS导出为excel文件
*/
export const jsToExcel = (id, name) => {
  //window.location.href='<%=basePath%>pmb/excelShowInfo.do';
  //获取表格
  var exportFileContent = document.getElementById(id).outerHTML;
  //编程设置格式为Excel,表格内容通过btoa转化为base64,此方法只在文件较小时使用(小于1M)
 BxAdOet //exportFileContent=window.btoa(unescape(encodeURIComponent(exportFileContent)));
  //var link = "data:"+MIMEType+";base64," + exportFileContent;
  //使用Blob
  var blob = new Blob([exportFileContent], { type: "text/plain;charset=utf-8" });     //解决中文乱码问题
  blob = new Blob([String.fromCharCode(0xFEFF), blob], { type: blob.type });
  //设置链接
  var link = window.URL.createObjectURL(blob);
  var a = document.createElement("a");  //创建a标签
  a.download = name; //设置被下载的超链接目标(文件名)  建议文件后缀为 .xls
  a.href = lijsnk;              //设置a标签的链接
  document.body.appendChild(a);      //a标签添加到页面
  a.click();                //设置a标签触发单击事件
  document.body.removeChild(a);      //移除a标签
}

使用方式   

  

<table id='table_report'>...</table>

<div onClick={() => jsToExcel('table_report', '现券交易异常日报.xls')}>导出</div>

如果想导出xlsx格式请参考方法2,方法1仅改文件后缀 不会被Excel识别  但是wps可以

2.使用xlsx导出(此方法导出的excel文件无样式,但导出的文件格式是 xlsx格式) 

首先安装xlsx  : yarn add xlsx

import XLSX from "xlsx"


/**
* 用XLSX导出 (导出无样式)
*/
export const exportExcel = (id, name) => {
  var exportFileContent = document.getElementById(id).cloneNode(true);
  var wb = XLSX.utils.table_to_book(exportFileContent, { sheet: "sheet1" });
  XLSX.writeFile(wb, name);
}
  

使用方式

  

<table id='table_report'>...</table>

<div onClick = {() => exportExcel('table_report', '现券交易异常日报.xlsx')}>导出</div>

3.使用 js-export-excel (可以导出多张sheet表)

首先安装 js-export-excel  : yarn add js-export-excel 

import { Table } from 'antd';
import { columns } from './config';
import ExportJsonExcel from "js-export-excel";
import { PlusCircleOutlined } from '@ant-design/icons';

function Tables(props) {
 const { isLoading, viewData, data } = props;
 // data格式
 const data1 = [
  {
   adID: "张三",
   leaveCount: 26,
   leaveDuration: 82,
   leaveType: "调休",
   name: "张三"
  },
  {
   adID: "张三1",
   leaveCount: 526,
   leaveDuration: 82,
   leaveType: "调休",
   name: "张三1"
  },
  {
   adID: "张三1",
   leaveCount: 26,
   leaveDuration: 852,
   leaveType: "调休",
   name: "张三1"
  },
  {
   adID: "张三1",
   leaveCount: 256,
   leaveDuration: 82,
   leaveType: "调休",
   name: "张三1"
  },
 ]
 /**
 * 导出数据
 */
 const handleExportCurrentExcel = (data) => {
  let sheetFilter = ["name", "leaveType", "leaveCount", "leaveDuration"];
  let sheetFilter2 = ["name", "leaveType", "leaveCount", "leaveDuration"];
  let option = {};
  option.fileName = '考勤分析结果';
  option.datas = [
   {
    sheetData: data1,
    sheetName: '考勤分析结果',
    sheetFilter: sheetFilter,
    sheetHeader: ['姓名', '类型', '次数', '时长'],
    columnWidths: [10, 10, 10, 10]
   },
   {
    sheetData: data1, //比较懒得造数据了 跟表1数据一样
    sheetName: '考勤分析结果222',
    sheetFilter: sheetFilter2,
    sheetHeader: ['姓名22', '类型22', '次数22', '时长22'],
    columnWidths: [10, 10, 10, 10]
   },
  ];
  var toExcel = new ExportJsonExcel(option); //new
  toExcel.saveExcel(); //保存
 }

 return (
  <div>
   <div className='exportButton' onClick={() => handleExportCurrentExcel(data)}>
    <PlusCircleOutlined className='icon-but' />
    导出当前数据
   </div>
   <Table
    loading={isLoading}
    columns={columns}
    dataSource={viewData}
    pagination={false}
   />
  </div>
 )
}
export default Tables;

4.第四种 使用react-html-table-to-excel   不推荐使用

安装   react-html-table-to-excel : yarn add react-html-table-to-excel

import React, { useRef, useEffect } from 'react';
import { Table } from "antd";
import { columns } from './config';
import ReactHTMLTableToExcel from 'react-html-table-to-excel';
import styles from './index.module.less';
function StudyExcel() {

  const data = [
    {
      key: '0',
      name: '张三'
    },
    {
      key: '1',
      name: '赵四'
    },
    {
      key: '2',
      name: '王五'
    },
    {
      key: '3',
      name: '齐六'
    }
  ];

  // 用ref来获取组件按钮实例,使用里面的方法
  const buttonRef = useRef(null);

  // 禁止组件按钮的默认点击事件
  useEffect(() => {
    const button = document.querySelector('#test-table-xls-button');
    button.style['pointer-events'] = ('none');
  }, []);


  // 导出表格
  const exportTable = (e) => {
    e.stopPropagation();
    const table = document.getElementsByTagName编程('table');
    const container = document.querySelector('#hiddenBox');
    const tempTable = document.createElement('table');
    tempTable.appendChild(table[0]);
    tempTable.setAttribute('id', 'table-to-xls');          // 给table添加id,值与按钮上的table字段对应
    container.appendChild(tempTable);                // 把创建的节点添加到页面容器中
    buttonRef.current.handleDownload();               // 手动触发下载
  };
  return (
    <div style={{ backgroundColor: '#fff' }} className={styles.container}>
      <span onClick={(e) => exportTable(e)}>
        <ReactHTMLTableToExcel
          width={1900}
          ref={buttonRef}
          table="table-to-xls"
          id='test-table-xls-button'
          filename='回购日报'
          sheet='表1'
          buttonText='导出Excel'
        />
      </span>
      <Table
        columns={columns}
        dataSource={data}
        bordered
        pagination={false}
      />
      <div id='hiddenBox' style={{ position: 'absolute', zIndex: -1, top: 0, left: 0 }} />
    </div>
  )
}
export default StudyExcel;

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。