React如何接收excel文件下載導(dǎo)出功能封裝
React接收excel文件下載導(dǎo)出功能封裝
因?yàn)樽罱?xiàng)目又需求要導(dǎo)出excel,所以封裝了這部分的功能,對fetch的封裝做了修改,使之后的調(diào)用導(dǎo)出功能更為方便
首先這個項(xiàng)目請求是對fetch進(jìn)行過封裝的 ,如果對fetch有了解的話,我們知道fetch種response返回的是一個實(shí)現(xiàn)了Body接口的對象, 所以可以使用Body接口中的方法 json()處理json,blob ()處理成blob文件對象 方法, 所以要先對封裝的請求方法做如下修改
export default function request(url, option,noToken = false,type = 'json') { ? //這是封裝request方法 noToken判斷是否寫代token ?type用來區(qū)別 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' ? ? ? ? ... ? ? ? ? } ? ? ? ?} ?? ?} }
上面我們通過一個參數(shù),將blob文件處理成url
export async function exportExcel(params) { ? return request(`/api/xxxxx/${params}`,{method: 'GET'} ,false ,'blob' ); } ?
上面就是我們導(dǎo)出文件的請求接口,獲得的是一個url,然后我們在effect中接受url
* exportExcel({payload}, {call,put}) { ? try { ? ? const url = yield call(exportExcel, payload); //收到一個url ?? ? let link = document.createElement('a') //創(chuàng)建一個a標(biāo)簽 ? ? ?link.style.display = 'none' //不顯示 ? ? ?link.href = url ?//將地址填入 ? ? ?link.setAttribute('download', '表格.xlsx') //設(shè)置下載屬性,取個文件名 ? ? ?document.body.appendChild(link) //添加到頁面上 ? ? ?link.click() //點(diǎn)擊觸發(fā)下載 ? } catch (e) { ? } },
到這里就是實(shí)現(xiàn)了文件的導(dǎo)出,基本原理就是將接受的文件處理成url,用a標(biāo)簽觸發(fā)下載
其實(shí)本來到這里就應(yīng)該結(jié)束了,但是作為一個有原則的程序員, 反復(fù)添加a標(biāo)簽顯示讓我們覺得很不規(guī)范, 所以我們來改寫成一直復(fù)用一個a標(biāo)簽來下載,動態(tài)修改url\\現(xiàn)在BasicLayout里加個a標(biāo)簽,因?yàn)檫@個是登陸都最先加載的,保證每個模塊都能使用
? ?<a ? ? ?style={{display: 'none'}}? ? ?ref={(link)=> {this.props.dispatch({type: 'global/saveLink', payload: link})}} //這個是用來講a標(biāo)簽的ref存到redux里,隨時可以調(diào)用 ? ?></a>
**然后我們在modes/global里寫兩個reducer**
? reducers: { ? ? saveLink(state, { payload }) { ? ? //保存a標(biāo)簽 ? ? ? return { ? ? ? ? ...state, ? ? ? ? link: payload, ? ? ? } ? ? }, ? ? exportFile(state, { payload }) { ? ? //設(shè)置a標(biāo)簽的地址并觸發(fā)點(diǎn)擊下載 ? ? ? state.link.href = payload.url ? ? ? state.link.setAttribute('download',payload.name) ? ? ? state.link.click() ? ? ? return { ? ? ? ? ...state, ? ? ? }; ? ? }, }
然后我們在普通的模塊中effect調(diào)用時只需要這么寫
* exportExcel({payload}, {call,put}) { ? try { ? ? const url = yield call(exportExcel, payload); //收到一個url ?? ?yield put({type: 'global/exportFile',payload: {url,name: `表格.xlsx`}}) //設(shè)置地址并觸發(fā)下載? ? } catch (e) { ? } },
這樣寫方便了很多 ,其實(shí)最好的方式是將這部分代碼封裝到一個組件中,單獨(dú)調(diào)用,這里就不演示了,寫法差不多
react導(dǎo)出excel文件的幾種方式
一共總結(jié)了四種方法 前兩種適用范圍比較廣泛 可以適用導(dǎo)出多級表頭合并等,第三種方法導(dǎo)出的文件比較中規(guī)中矩,但是支持導(dǎo)出多張sheet表。第四種方法導(dǎo)出不推薦使用
1.原生js導(dǎo)出 (帶樣式)
/** ?* ?原生JS導(dǎo)出為excel文件 ?*/ export const jsToExcel = (id, name) => { ? ? //window.location.href='<%=basePath%>pmb/excelShowInfo.do'; ? ? //獲取表格 ? ? var exportFileContent = document.getElementById(id).outerHTML; ? ? //設(shè)置格式為Excel,表格內(nèi)容通過btoa轉(zhuǎn)化為base64,此方法只在文件較小時使用(小于1M) ? ? //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 }); ? ? //設(shè)置鏈接 ? ? var link = window.URL.createObjectURL(blob); ? ? var a = document.createElement("a"); ? ?//創(chuàng)建a標(biāo)簽 ? ? a.download = name; ?//設(shè)置被下載的超鏈接目標(biāo)(文件名) ? 建議文件后綴為 .xls ? ? a.href = link; ? ? ? ? ? ? ? ? ? ? ? ? ? ?//設(shè)置a標(biāo)簽的鏈接 ? ? document.body.appendChild(a); ? ? ? ? ? ?//a標(biāo)簽添加到頁面 ? ? a.click(); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//設(shè)置a標(biāo)簽觸發(fā)單擊事件 ? ? document.body.removeChild(a); ? ? ? ? ? ?//移除a標(biāo)簽 }
使用方式
<table id='table_report'>...</table> ? <div onClick={() => jsToExcel('table_report', '現(xiàn)券交易異常日報(bào).xls')}>導(dǎo)出</div>
如果想導(dǎo)出xlsx格式請參考方法2,方法1僅改文件后綴 不會被Excel識別 但是wps可以
2.使用xlsx導(dǎo)出(此方法導(dǎo)出的excel文件無樣式,但導(dǎo)出的文件格式是 xlsx格式)
首先安裝xlsx : yarn add xlsx
import XLSX from "xlsx" ? ? /** ?* ?用XLSX導(dǎo)出 (導(dǎo)出無樣式) ?*/ 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', '現(xiàn)券交易異常日報(bào).xlsx')}>導(dǎo)出</div>
3.使用 js-export-excel (可以導(dǎo)出多張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: "調(diào)休", ? ? ? name: "張三" ? ? }, ? ? { ? ? ? adID: "張三1", ? ? ? leaveCount: 526, ? ? ? leaveDuration: 82, ? ? ? leaveType: "調(diào)休", ? ? ? name: "張三1" ? ? }, ? ? { ? ? ? adID: "張三1", ? ? ? leaveCount: 26, ? ? ? leaveDuration: 852, ? ? ? leaveType: "調(diào)休", ? ? ? name: "張三1" ? ? }, ? ? { ? ? ? adID: "張三1", ? ? ? leaveCount: 256, ? ? ? leaveDuration: 82, ? ? ? leaveType: "調(diào)休", ? ? ? name: "張三1" ? ? }, ? ] ? /** ? ?* ?導(dǎo)出數(shù)據(jù) ? ?*/ ? const handleExportCurrentExcel = (data) => { ? ? let sheetFilter = ["name", "leaveType", "leaveCount", "leaveDuration"]; ? ? let sheetFilter2 = ["name", "leaveType", "leaveCount", "leaveDuration"]; ? ? let option = {}; ? ? option.fileName = '考勤分析結(jié)果'; ? ? option.datas = [ ? ? ? { ? ? ? ? sheetData: data1, ? ? ? ? sheetName: '考勤分析結(jié)果', ? ? ? ? sheetFilter: sheetFilter, ? ? ? ? sheetHeader: ['姓名', '類型', '次數(shù)', '時長'], ? ? ? ? columnWidths: [10, 10, 10, 10] ? ? ? }, ? ? ? { ? ? ? ? sheetData: data1, ?//比較懶得造數(shù)據(jù)了 ?跟表1數(shù)據(jù)一樣 ? ? ? ? sheetName: '考勤分析結(jié)果222', ? ? ? ? sheetFilter: sheetFilter2, ? ? ? ? sheetHeader: ['姓名22', '類型22', '次數(shù)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' /> ? ? ? ? 導(dǎo)出當(dāng)前數(shù)據(jù) ? ? ? </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來獲取組件按鈕實(shí)例,使用里面的方法 ? ? const buttonRef = useRef(null); ? ? ? // 禁止組件按鈕的默認(rèn)點(diǎn)擊事件 ? ? useEffect(() => { ? ? ? ? const button = document.querySelector('#test-table-xls-button'); ? ? ? ? button.style['pointer-events'] = ('none'); ? ? }, []); ? ? ? ? // 導(dǎo)出表格 ? ? 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字段對應(yīng) ? ? ? ? container.appendChild(tempTable); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?// 把創(chuàng)建的節(jié)點(diǎn)添加到頁面容器中 ? ? ? ? buttonRef.current.handleDownload(); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?// 手動觸發(fā)下載 ? ? }; ? ? 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='回購日報(bào)' ? ? ? ? ? ? ? ? ? ? sheet='表1' ? ? ? ? ? ? ? ? ? ? buttonText='導(dǎo)出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;
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
使用 Rails API 構(gòu)建一個 React 應(yīng)用程序的詳細(xì)步驟
這篇文章主要介紹了使用 Rails API 構(gòu)建一個 React 應(yīng)用程序的詳細(xì)步驟,主要包括后端:Rails API部分,前端:React部分及React組件的相關(guān)操作,具有內(nèi)容詳情跟隨小編一起看看吧2021-08-08JS中使用react-tooltip插件實(shí)現(xiàn)鼠標(biāo)懸浮顯示框
前段時間遇到的一個需求,要求鼠標(biāo)懸停顯示使用描述, 用到了react-tooltip插件,今天寫一個總結(jié),感興趣的朋友跟隨小編一起看看吧2019-05-05React路由參數(shù)傳遞與嵌套路由的實(shí)現(xiàn)詳細(xì)講解
這篇文章主要介紹了React路由參數(shù)傳遞與嵌套路由的實(shí)現(xiàn),嵌套路由原則是可以無限嵌套,但是必須要讓使用二級路由的一級路由匹配到,否則不顯示,需要的朋友可以參考一下2022-09-09react PropTypes校驗(yàn)傳遞的值操作示例
這篇文章主要介紹了react PropTypes校驗(yàn)傳遞的值操作,結(jié)合實(shí)例形式分析了react PropTypes針對傳遞的值進(jìn)行校驗(yàn)操作相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2020-04-04React?useEffect不支持async?function示例分析
這篇文章主要為大家介紹了React?useEffect不支持async?function示例分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07React中實(shí)現(xiàn)編輯框自動獲取焦點(diǎn)與失焦更新功能
在React應(yīng)用中,編輯框的焦點(diǎn)控制和數(shù)據(jù)回填是一個常見需求,本文將介紹如何使用useRef和useEffect鉤子,在組件中實(shí)現(xiàn)輸入框自動獲取焦點(diǎn)及失焦后更新數(shù)據(jù)的功能,文中通過代碼示例給大家講解的非常詳細(xì),需要的朋友可以參考下2024-01-01React項(xiàng)目中報(bào)錯:Parsing error: The keyword &a
ESLint 默認(rèn)使用的是 ES5 語法,如果你想使用 ES6 或者更新的語法,你需要在 ESLint 的配置文件如:.eslintrc.js等中設(shè)置 parserOptions,這篇文章主要介紹了React項(xiàng)目中報(bào)錯:Parsing error: The keyword 'import' is reservedeslint的問題及解決方法,需要的朋友可以參考下2023-12-12React-hook-form-mui基本使用教程(入門篇)
react-hook-form-mui可以幫助開發(fā)人員更輕松地構(gòu)建表單,它結(jié)合了React?Hook?Form和Material-UI組件庫,使用react-hook-form-mui,開發(fā)人員可以更快速地構(gòu)建表單,并且可以輕松地進(jìn)行表單驗(yàn)證和數(shù)據(jù)處理,本文介紹React-hook-form-mui基本使用,感興趣的朋友一起看看吧2024-02-02