欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

用于文件下载的 React 文件流

最编程 2024-07-17 14:30:16
...

同种方法-两种方案:

第一种:页面上自己手动添加a标签
第二种:js自动生成a标签(推荐第二种)

今天在react项目开发过程中,有这样的一个需求就是文件下载。
自己认为:通过接口请求后端发给返给自己的会是一个文件下载的地址或者路径什么的,只要把这个地址赋值给a链接即可
实际情况:后端发给我的是一端文件流,那么就是需要们自动去解析文件流,然后把解析出来的数据,通过a标签进行下载

第一种方案:
//点击文件下载
<div style={styles.downFileBtn}
           onClick={(event) => {
             event.preventDefault();
             event.stopPropagation();
             fetch(downloadFiles, { //downloadFiles 接口请求地址
               method: 'get',
               credentials: 'include',
               headers: new Headers({
                 'Content-Type': 'application/json',
                 'X-Auth-Token': User.getToken(),//设置header 获取token
               })
             }).then((response) => {
               response.blob().then(blob => {
                 let blobUrl = window.URL.createObjectURL(blob);
                 let aElement = document.getElementById('downloadDiv'); //获取a标签元素
                 let filename = times.formatNowDate() + '.zip';//设置文件名称
                 aElement.href = blobUrl;//设置a标签路径
                 aElement.download = filename;
                 aElement.click();
                 window.URL.revokeObjectURL(blobUrl);
               });
             }).catch((error) => {
               console.log('文件下载失败', error);
             });
           }}
      >
        <Icon type="download"/>文件下载
      </div>

//定义个a标签数组
const Anchor = props => {
  return (
    <a {...props}>{props.children}</a>
  );
};

//页面上使用a标签数组
<Anchor id="downloadDiv" style={{display: 'none'}}></Anchor> //隐藏不显示
第二种方案:(这块我封装了一个组件)
/**
 * @desc:这是一个文件下载组件
 * @param:参数说明
 *    api_url:接口地址
 *    icon: 下载图片设置
 *    text: 下载文本设置
 *    downFileBtnClass: 按钮样式设置
 */
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {Button, Icon} from 'antd';
import User from '/utils/user';
import times from '_TOOLS_/times';
import styles from './index.less';

const downFileBtn = styles.downFileBtn;

class FileDown extends PureComponent {
  constructor(props) {
    super(props);
    this.state = {
      loadingStatus: true,
      buttonDisabled: false
    }
  }

  //文件下载操作
  handleDownFile = (event, api_url) => {
    event.preventDefault();
    event.stopPropagation();
    //开启loading 按钮置灰
    this.setState({
      loadingStatus: false,
      buttonDisabled: true,
    });
    fetch(api_url, {
      method: 'get',
      credentials: 'include',
      headers: new Headers({
        'Content-Type': 'application/json',
        'X-Auth-Token': User.getToken(),
      }),
    }).then((response) => {
      response.blob().then(blob => {
        //关闭loading 按钮恢复正常
        this.setState({
          loadingStatus: true,
          buttonDisabled: false,
        });
        let blobUrl = window.URL.createObjectURL(blob);
        const filename = times.formatNowDate() + '.zip';
        const aElement = document.createElement('a');
        document.body.appendChild(aElement);
        aElement.style.display = 'none';
        aElement.href = blobUrl;
        aElement.download = filename;
        aElement.click();
        document.body.removeChild(aElement);
      });
    }).catch((error) => {
      //关闭loading 按钮恢复正常
      this.setState({
        loadingStatus: false,
        buttonDisabled: false,
      });
      console.log('文件下载失败', error);
    });
  };

  render() {
    const {api_url, text, icon, downFileBtnClass} = this.props;
    const {loadingStatus, buttonDisabled} = this.state;
    return (
      <Button
        type="primary"
        className={downFileBtnClass}
        onClick={(event) => this.handleDownFile(event, api_url)}
        disabled={buttonDisabled}
      >
        <Icon type={loadingStatus ? icon : 'loading'}/>
        {loadingStatus ? text : '下载中...'}
      </Button>
    );
  }
}

//定义属性 类型以及是否必填项
FileDown.proTypes = {
  api_url: PropTypes.isRequired
};
//定义属性的默认值
FileDown.defaultProps = {
  text: '文件下载',
  icon: 'download',
  downFileBtnClass: downFileBtn,
};
export default FileDown;