element-ui upload组件的http-request自定义上传文件
element-ui的upload上传组件(upload组件文档地址),默认以提供action上传地址的方式上传文件,但如果我们使用七牛或者阿里oss上传文件的话,upload这种默认上传文件的方式就行不通了,因为阿里oss等自定义上传接口,往往都有权限,额外的配置参数等限制,所以我们就需要自定义上传接口啦,好在upload组件提供了http-request属性可以让我们自定义上传api
开始着手实现自定义上传吧
使用方法
页面使用模板部分 upload 组件截图如下
methods 中自定义上传方法js代码截图如下
其中 ossUpload 为我们传递给upload组件的自定义上传方法,ossUploadApi为真正的上传文件数据到服务器的api,到这里,就已经可以触发自定义上传文件函数啦。
关联上传钩子
这里有一个问题,因为对于upload上传组件来说,不仅仅有上传文件,还有上传文件成功 success 和失败 error 钩子,需要我们对上传成功和上传失败做一些处理才行。
在没有自定义上传文件前,这些上传钩子是和上传文件请求接口相关联的。而我们自定义了上传文件操作,所以现在上面的写法是不能主动触发upload组件定义的钩子的。
那么我们怎么把自定义上传api和upload组件的这两个钩子关联起来呢,element-ui文档上介绍提供了 http-request 属性可以让我们可以自定义上传,没有介绍如何使用,这个时候就要发挥我们码农看源代码的能力啦。通过断点源码找到调用我们自定义上传文件方法的地方,如下图所示
通过截图上面的文字分析,我们添加如下所示代码即可,即添加return 语句返回promise 结果 ,(注意,因为ossUploadApi这个接口本身实现的时候返回的就是promise(由自己实现返回promise)),所以添加 return 语句返回即可
同时,通过源码我们也发现,upload组件内部往我们自定的上传方法中传递了一个options参数,其中包含了对upload上传文件 success 成功钩子,error 失败钩子,progress 上传进度钩子,也就是说,其实我们也可以在自定义上传里面主动调用这些钩子以实现相应功能(注意自己调用钩子时候保证回调参数一致)。
回调数据
打印自定义上传方法的回调数据(由upload组件内部传递给我们的数据,通过上面源码分析截图调用 httpRequest 的地方,也可以看到回调数据的)
总结:
一,通过 http-request 属性可以让我们自定义上传 api 方法
二,我们有两种方案可以将自定义上传方法和upload内部的文件上传 success,error 钩子关联起来
①,自定义上传方法并返回promise (推荐)
②,在自定义上传方法中主动调用upload组件提供的钩子或者调用自己定义的钩子
完整代码如下
<template> <el-upload ref="upload" :action="doUpload" :headers="headers" :http-request="ossUpload" :on-preview="handlePictureCardPreview" :on-remove="handleRemove" :on-success="handleSuccess" :on-error="handleError" :before-upload="beforeUpload" :file-list="fileList" :disabled="disable" > <el-button size="small" :disabled="disable" type="primary" > 上传文件 </el-button> <div slot="tip" class="el-upload__tip" > 支持jpg、png、pdf、word格式,大小不超过500M。 </div> </el-upload> </template> <script> import { getToken } from '@/utils/auth'; import { ossUploadApi } from '@/api/serviceProvider'; export default { name: 'Upload', model: { prop: 'fileList', event: 'change', }, props: { fileList: { type: Array, required: true, }, disable: { type: Boolean, default: false, }, }, data() { return { // 上传地址 doUpload: process.env.VUE_APP_BASE_API + (process.env.NODE_ENV === 'production' ? '' : '/api') + process.env.VUE_APP_BASE_CONTENT_URL + '/contract/upload', // doUpload: 'https://jsonplaceholder.typicode.com/posts/', // 下载请求头 headers: { tgt: getToken(), }, }; }, watch: {}, methods: { // 处理文件点击预览操作 handlePictureCardPreview(file) { console.log(file); let downUrl = ''; if (file.hasOwnProperty('url')) { downUrl = file.url; } else { downUrl = file.response.message; } // 赋值 const a = document.createElement('a'); // 创建href属性 a.href = downUrl; // 点击下载 a.click(); }, // 上传前 beforeUpload(file) { const limitSize = 500; const isLt500M = file.size / 1024 / 1024 < limitSize; if (!isLt500M) { this.$message.error(`上传文件大小不能超过 ${limitSize}MB!`); } return isLt500M; }, // 手动删除文件钩子 handleRemove(_file, fileList) { console.log(fileList); this.processFileList(fileList); }, // 上传成功钩子 handleSuccess(_res, _file, fileList) { console.log(fileList); this.processFileList(fileList); }, // 上传失败的钩子 handleError(err, _file, fileList) { if (err.code !== 200) { this.$message({ message: err.message || '上传失败', type: 'warning', }); } this.processFileList(fileList); }, // 自定义处理filelist processFileList(fileList) { fileList.forEach((item) => { if (!item.url && item.response) { const response = item.response; item.url = response.url; } }); this.triggerChange(fileList); }, triggerChange(fileList) { this.$emit('change', fileList); }, // 自定义上传oss方法 ossUpload(option) { const file = option.file; return ossUploadApi(file); }, }, }; </script> <style lang="scss" scoped></style>