赞
踩
最近在用uni-app写项目的时候 有业务需要同时上传多张图片给后台,但查了官方文档,发现uni.uploadFile()
虽然可以通过 files
参数上传多个文件,但是只支持APP和H5。
我的项目主要针对的是微信小程序,所以看了很多文章,找到如下两种方式,可以参考一下
使用 uni.chooseMedia 成功后会返回 本地临时文件列表
可以参考官方文档 uni.chooseMedia()
uni.chooseMedia({
mediaType: ['image'],
sourceType: ['album'],
success: (res) => {
const { tempFiles } = res
// uploadFile 方法为自己封装的上传方法
uploadFile(tempFiles)
},
fail: () => {
console.log('fail')
},
complete: () => {
// console.log('complete')
},
})
成功后调用自己写的 uploadFile
const uploadFile = (files:any[]) => { const uploadTasks = files.map((file: any, index: number) => { return new Promise((resolve, reject) => { const uploadTask = uni.uploadFile({ url: 'https://www.xxx.cn/v1/wxInvoice/upload', // 接口地址 filePath: file.tempFilePath, // 临时文件路径 name: 'files[]', // 服务器接收的文件字段名(这个地方很重要要和后端沟通一下) header: { Authorization: 'Bearer ' + token.value, 'Content-Type': 'multipart/form-data', }, formData: { // 可以在这里添加额外的formData参数 }, success: function (res) { resolve(res.data) }, fail: function (err) { reject(err) }, }) // 这里可以根据需要显示进度条 uploadTask.onProgressUpdate((res) => { console.log('上传进度', res.progress) console.log('已经上传的数据长度', res.totalBytesSent) console.log('预期需要上传的数据总长度', res.totalBytesExpectedToSend) }) }) }) Promise.all(uploadTasks) .then((res) => { console.log('上传成功', res) // 上传成功后的操作 }) .catch((err) => { console.log('上传失败', err) // 上传失败后的操作 }) }
使用 wx-formdata 库,当然我这里是uni-app + ts
项目,所以我把这个库里的 formData.js
和 mimeMap.js
库进行了修改,文章结尾看(不要介意代码质量,能跑就行)
使用
uni.chooseMedia({ mediaType: ['image'], sourceType: ['album'], success: (res) => { const { tempFiles } = res const formData = new FormData() // 非文件用 append()方法 // 文件用 appendFile()方法 // 需要遍历将文件加入到formData中(这里是我的需求,可自定义) for (let i = 0; i < tempFiles .length; i++) { formData.appendFile('files[' + i + ']', tempFiles [i].tempFilePath) } const data = formData.getData() // 调用接口传递数据 uni.request({ url: '接口地址', method: 'post', data: data.buffer, header: { 'Content-Type': data.contentType }, success:() => { //... } }) }, fail: () => { console.log('fail') }, complete: () => { // console.log('complete') }, })
以下是修改过的文件
formData.ts
import mimeMap from './mimeMap' interface CommonFormData { fileManager: any data: any files: any append(name: string, value: any): boolean appendFile(name: string, path: any, fileName?: any): boolean getData(): any } class FormData implements CommonFormData { fileManager: any data: any files: any constructor() { this.fileManager = uni.getFileSystemManager() this.data = {} this.files = [] } append(name: string, value: any) { this.data[name] = value return true } appendFile(name: string, path: any, fileName?: any) { let buffer = this.fileManager.readFileSync(path) if (Object.prototype.toString.call(buffer).indexOf('ArrayBuffer') < 0) { return false } if (!fileName) { fileName = getFileNameFromPath(path) } this.files.push({ name: name, buffer: buffer, fileName: fileName, }) return true } getData() { return convert(this.data, this.files) } } function getFileNameFromPath(path: any) { let idx = path.lastIndexOf('/') return path.substr(idx + 1) } function convert(data: any, files: any) { let boundaryKey = 'unimpFormBoundary' + randString() // 数据分割符,一般是随机的字符串 let boundary = '--' + boundaryKey let endBoundary = boundary + '--' let postArray: any = [] //拼接参数 if (data && Object.prototype.toString.call(data) == '[object Object]') { for (let key in data) { postArray = postArray.concat(formDataArray(boundary, key, data[key])) } } //拼接文件 if (files && Object.prototype.toString.call(files) == '[object Array]') { for (let i in files) { let file = files[i] postArray = postArray.concat(formDataArray(boundary, file.name, file.buffer, file.fileName)) } } //结尾 let endBoundaryArray = [] endBoundaryArray.push(...endBoundary.toUtf8Bytes()) postArray = postArray.concat(endBoundaryArray) return { contentType: 'multipart/form-data; boundary=' + boundaryKey, buffer: new Uint8Array(postArray).buffer, } } // 获取随机字符串 function randString() { var result = '' var chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' for (var i = 17; i > 0; --i) result += chars[Math.floor(Math.random() * chars.length)] return result } function formDataArray(boundary: any, name: string, value: any, fileName?: string) { let dataString: any = '' let isFile = !!fileName dataString += boundary + '\r\n' dataString += 'Content-Disposition: form-data; name="' + name + '"' if (isFile) { dataString += '; filename="' + fileName + '"' + '\r\n' dataString += 'Content-Type: ' + getFileMime(fileName || '') + '\r\n\r\n' } else { dataString += '\r\n\r\n' dataString += value } var dataArray = [] dataArray.push(...dataString.toUtf8Bytes()) if (isFile) { let fileArray = new Uint8Array(value) dataArray = dataArray.concat(Array.prototype.slice.call(fileArray)) } dataArray.push(...'\r'.toUtf8Bytes()) dataArray.push(...'\n'.toUtf8Bytes()) return dataArray } function getFileMime(fileName: string) { let idx = fileName.lastIndexOf('.') let index: string = fileName.substr(idx) let mime = mimeMap[index] return mime ? mime : 'application/octet-stream' } function stringToUtf8(string: string) { let encoder = new TextEncoder() return encoder.encode(string) } String.prototype.toUtf8Bytes = function () { var str: any = this var bytes = [] for (var i = 0; i < str.length; i++) { bytes.push(...str.utf8CodeAt(i)) if (str.codePointAt(i) > 0xffff) { i++ } } return bytes } String.prototype.utf8CodeAt = function (i: any) { var str = this var out = [], p = 0 var c = str.charCodeAt(i) if (c < 128) { out[p++] = c } else if (c < 2048) { out[p++] = (c >> 6) | 192 out[p++] = (c & 63) | 128 } else if ((c & 0xfc00) == 0xd800 && i + 1 < str.length && (str.charCodeAt(i + 1) & 0xfc00) == 0xdc00) { // Surrogate Pair c = 0x10000 + ((c & 0x03ff) << 10) + (str.charCodeAt(++i) & 0x03ff) out[p++] = (c >> 18) | 240 out[p++] = ((c >> 12) & 63) | 128 out[p++] = ((c >> 6) & 63) | 128 out[p++] = (c & 63) | 128 } else { out[p++] = (c >> 12) | 224 out[p++] = ((c >> 6) & 63) | 128 out[p++] = (c & 63) | 128 } return out } export default FormData
mimeMap.ts
const mimeMap:{[key:string]:any = {
// 此处省略...
// 把一些重复的处理一下
}
formData.d.ts
interface String {
toUtf8Bytes(): any
utf8CodeAt(i:any): any
}
以上就是我的分享,有问题留言
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。