美文网首页
实现上传下载进度条和取消ajax请求

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

作者: ThemisHoo | 来源:发表于2019-10-15 20:01 被阅读0次

    一、实现功能点:

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

    二、知识点:

    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 (
                <div className="process-content operation-content">
                                <Modal
                                    title={textLoad ? '正在上传' : '正在下载'}
                                    visible={visibleLoad}
                                    footer={null}
                                    onCancel={this.handleCancelLoad}
                                    >
                                    {
                                        loadList.length && loadList.map((ele, index) => {
                                            return <Row key={index}>
                                                <Col span={5}>{ele.fileName.length <= 21 ? ele.fileName : `${ele.fileName.substring(0, 5)}...${ele.fileName.substring(ele.fileName.length-16,ele.fileName.length)}`}</Col>
                                                <Col span={19}><Progress percent={ele.percent} status={ele.status}/></Col>
                                            </Row>
                                        })
                                    }
                                    <Row style={{borderTop: '1px solid #dddee3', paddingTop: '20px'}}><Col span={2} offset={22}>
                                        <Button onClick={this.handleCancelLoad}>{textLoad ? '取消上传' : '取消下载'}</Button>
                                    </Col></Row>
                                </Modal>
                            </div>
                        </div>
                    </div>
                </div>
            )
        }
    }
    
    

    相关文章

      网友评论

          本文标题:实现上传下载进度条和取消ajax请求

          本文链接:https://www.haomeiwen.com/subject/sqbjmctx.html