实现上传下载进度条和取消ajax请求

一、实现功能点:

1.传输文件进度条展示
2.传输过程中可取消
3.实现多文件上传下载进度展示

实现上传下载进度条和取消ajax请求_第1张图片

二、知识点:

axios的config中封装了onDownloadProgress(下载进度),onUploadProgress(上传进度),cancelToken(取消请求)的方法

1、onDownloadProgress为下载进度方法,在下载文件时被实时调用,返回的progress.loaded为已经下载的文件大小,total在下载时拿不到,只能通过下载前获取文件大小。
注:测试过程中发现,如果下载文件过小,如几十K,onDownloadProgress 不会被调用。此时下载速度非常快,可以在then和catch方法中直接处理进度
 axios({
   url: 'xxx',
   method: 'get',
   onDownloadProgress (progress) {
     console.log(Math.round(progress.loaded / total * 100) + '%');
   }
 })
2、onUploadProgress为上传进度的方法,在上传文件时被实时调用,返回的progress.loaded为已经上传的文件大小,progress.total为总文件大小。
注:在下载请求中,也会调用一次onUploadProgress方法。
axios({
   url: 'xxx',
   method: 'post',
   onDownloadProgress (progress) {
     console.log(Math.round(progress.loaded / progress.total * 100) + '%');
   }
 })
3、cancelToken为取消请求方法,每个请求有唯一token,多个请求同时存在时,可以通过token区分关闭哪个请求。

有两种调用方式,我使用的是第二种

方法一
const CancelToken = axios.CancelToken;
const source = CancelToken.source();

axios.get('/url', {
  cancelToken: source.token
}).catch(function (thrown) {
  if (axios.isCancel(thrown)) {
    console.log('Request canceled', thrown.murlessage);
  } else {
    // handle error
  }
});

axios.post('/user/12345', {
  name: 'new name'
}, {
  cancelToken: source.token
})

// 取消请求时调用此方法
source.cancel('Operation canceled by the user.');
方法二
const CancelToken = axios.CancelToken;
let cancel;

axios.get('/url', {
  cancelToken: new CancelToken(function executor(c) {
    // An executor function receives a cancel function as a parameter
    cancel = c;
  })
});

// 取消请求时调用方法
cancel();

三、完整代码(可忽略)

主要记录多个上传下载,对cancelToken和页面显示的处理逻辑,只要了解上传下载和取消请求的原理即可,此部分可忽略。

import React, { Component } from 'react';
import axios from 'axios';

const CancelToken = axios.CancelToken;
// 创建一个数组,存放所有请求的cancelToken的对象
let cancelList = []

export default class BaseCompnent extends Component {
    state = {};
  
    // 取消请求时调用的方法
    cancelAllAjax = () => {
        cancelList.map(e => {
             // 执行每个取消请求方法
            e()
        })
    }
    // 存放所有的请求句柄
    request = {
        get: (url, params, options) => {},
        post: (url, params, options) => {
            return axios.post(url, params, {
                cancelToken: new CancelToken((c) => {
                    //   将所有请求push到cancelList中
                    cancelList.push(c)
                }),
                ...options,
                headers: (Object.assign({}, (options || {}).headers || {}, {'X-Requested-With': 'XMLHttpRequest', 'returnurl': returnUrl, 'token': token})),
            }).then(this.resolveFilter, this.rejectFilter);
        },
        postTest: (url, params, options) => {},
        del: (url, params, options) => {};

    componentWillUnmount() {
        // 组件卸载之后,打断所有未结束得请求,
        // 子类要是要使用componentWillUnmount,需要显示的调用super.componentWillUnmount();
        this.cancelAllAjax()
    }
}

import React, { Component } from 'react';
import { BaseComponent } from 'components';

import { Button, message, Modal, Row, Col, Select, Progress } from 'antd';
const Option = Select.Option;

export default class Operation extends BaseComponent {
    constructor(props) {
        super(props);
        this.state = {
            visibleLoad: false, // 上传下载进度条模态框
            loadList: [], // 进度条列表
            textLoad: true, // 上传下载进度title
        }
    }

    componentWillMount() {}

    componentDidMount() {}

    // 下载文件流接口
    getFileStrem = (fileName, iconType, fileSize, markType) => {
        let { loadList } = this.state
        loadList.push({
            fileName: fileName,
            percent: 0,
            uid: fileName, // 这里最好不要用文件名做唯一标识,我懒~
            status: 'active'
        })
        this.setState({
            visibleLoad: true,
            textLoad: false
        })

        this.request.post('/proxy/file/download',  {
            responseType: 'blob',
            // 处理下载文件进度
            onDownloadProgress : progressEvent => {
                let percent = progressEvent.loaded / fileSize * 100 | 0
                let { loadList } = this.state
                // 将每个进度push到loadList中,用于页面展示
                loadList.forEach((ele, idex) => {
                    if (ele.uid == fileName) {
                        let lc = {
                            fileName: fileName,
                            percent: percent,
                            uid: fileName,
                            status: 'active'
                        }
                        loadList[idex] = lc
                        this.setState({
                            loadList
                        })
                    }
                })
            },
        }).then((res) => {}).catch((err) => {});
    }

    // 上传文件
    uploadFile = (MultipartFile, type, markType) => {
        let { loadList } = this.state
        loadList.push({
            fileName: MultipartFile.name,
            percent: 0,
            uid: MultipartFile.uid, // 上传文件可以直接拿到文件的uid,这里直接使用
            status: 'active'
        })
        this.setState({
            visibleLoad: true,
            textLoad: true
        })
        var formData = new FormData()
        formData.append('fileData', MultipartFile, MultipartFile.name)
        this.request.post('/proxy/file/upload', formData, {
            headers: {
                'Content-Type': 'multipart/form-data',
            },
            // 处理上传进度
            onUploadProgress: progressEvent => {
                let percent = progressEvent.loaded / progressEvent.total * 100 | 0
                let { loadList } = this.state
                // 将每个上传进度push进 loadList,用于页面展示
                loadList.forEach((ele, idex) => {
                    if (ele.uid == MultipartFile.uid) {
                        let lc = {
                            fileName: MultipartFile.name,
                            percent: percent,
                            uid: MultipartFile.uid,
                            status: percent === 100 ? 'success' : 'active'
                        }
                        loadList[idex] = lc
                        this.setState({
                            loadList
                        })
                    }
                })
            }
        }).then(res => {}).catch(err => {});
    }

  handleCancelLoad = () => {
        this.setState({
            visibleLoad: false,
            loadList: []
        })
        // 取消所有请求
        this.cancelAllAjax()
    }
  
    render() {
        const {visibleLoad, loadList, textLoad} = this.state    
        return (
            
{ loadList.length && loadList.map((ele, index) => { return {ele.fileName.length <= 21 ? ele.fileName : `${ele.fileName.substring(0, 5)}...${ele.fileName.substring(ele.fileName.length-16,ele.fileName.length)}`} }) }
) } }

你可能感兴趣的:(实现上传下载进度条和取消ajax请求)