使用 Element UI 上传组件 实现文件上传功能

474 阅读1分钟

主要记录使用 upload 组件上传文件要显示上传进度条的问题

模版部分

    // format 为支持的格式类型数组
    const format = ['png', 'jpg', 'zip', 'txt', 'doc', 'docx', 'csv', 'xls', 'xlsx', 'mp3', 'mp4', 'pdf', 'rar', 'jpeg', 'ppt', 'm4a', 'mov']

    <el-upload
        ref="upload"
        class="upload-file"
        action={this.action}
        accept={format.map(f => '.' + f.trim()).join(',')} // 转换成 accept 接受的数据格式
        drag
        multiple
        before-upload={this.beforeUpload}
        limit={5}
        http-request={this.handleUpload}
        file-list={this.fileList} // 文件列表,实际没啥用感觉,如果不是需求需要这个的话
        // 第一个恶心的地方,upload的这些 on-xxx 的钩子函数对于函数式组件来说非常不友好
        
        {...{props: {
            'on-remove': (file, list) => this.onRemoveFile(file, list),
            'on-exceed': () => {
                    this.$message({
                        message: '文件超出个数',
                        type: 'warning',
                    })
                }
            }}}
    >
        <i class="el-icon-upload"></i>
        <div class="el-upload__text">上传文案</div>
        <div slot="tip" class="el-upload__tip" domPropsInnerHTML={'上传提示语'}></div>
    </el-upload>

函数部分

    handleUpload(e) {
        /*
            e 是上传的文件的一些信息和方法
            如果只关心上传那就不需要写 promise,但是要在页面展示文件上传的状态就需要写promise 来抛出文件上传的一些状态
        */
        const prom = new Promise((resolve, reject) => {
            let args = {file: e.file}
            args = this.$injectCancelToken(args, String(e.file.cancelToken)); // axios 配置的 CancelToken 用来中断请求
            this.uploadLoading = true

            this.uploadModel.fetch(args, {config: {
                // axios 的请求配置;处理原生进度事件 // 浏览器专属
                onUploadProgress: (progressEvent) => {
                    const { loaded, total } = progressEvent
                    // 计算百分比
                    const complete = parseInt(((loaded / total) * 100) | 0, 10)
                    // 调用 upload 的 onProgress方法 显示文件上传的进度条
                    e.onProgress({percent: complete})
                }
            }}).then(res => {
                if(res.code === 10068) {
                    // 文件上传失败 调用 onError
                    e.onError()
                    return reject()
                }
                if(res.code === 200) {
                    this.$set(this.form.files, e.file.uid, res.data.file_path)
                    return resolve()
                }
            }).finally(() => {
                this.uploadLoading = false
            })
        })
        // !!!一定要写 abort,不然文件上传过程中取消上传会报错
        prom.abort = () => {}

        return prom
    },
    beforeUpload(file) {
        const maxSize = 1024 * 1024 * 30
        if(file.size > maxSize) {
            this.$message.error('文件大小超出上传限制')
            return false
        }
        // 在文件上传之前手动给file对象加上唯一标识 用于取消操作。实际不写也行,它文件会生成一个id 也是当前时间戳
        const uniq = new Date().valueOf()
        file.cancelToken = uniq
        return true
    },
    onRemoveFile(file, list) {
        let cancelToken = String(file.raw.cancelToken)
        this.$cancelRequestByToken(cancelToken)
        this.form.files[file.uid] = ''
    }