需要解决的问题
微信浏览器打开h5网页,项目要求选择上传文件的时候,能上传图片、视频、文件(.zip, .rar, .docx等),并兼容Android和ios。
注意
- uni.uploadFile只支持image、video、audio三种文件格式

所以上传文件(.zip, .rar, .docx等)只能自定义,上传图片和视频可以采取uniapp自带的方法
- uni.request传入FormData会报错
fail parameter `data`. Expected Object, String, Array, ArrayBuffer, got FormData
官方文档表示它只支持Object/String/ArrayBuffer三种类型的data
那就只能采取原生的XMLHttpRequest去做了。
本来想着既然如此,那索性就统一接口,所有文件都通过自定义input(type=”file”)的方法上传,但是在ios测试的时候,发现当调起图片和视频的时候,并不能拿到相应的数据,那就先分开来写三个不同的方法上传,分别是上传文件(自定义input)、图片(uni.chooseImage)和视频(uni.chooseVideo)
可选择上传方式
思路
当用户点击“选择文件”按钮的时候,跳出三个选项,分别调用不同的上传方法
按钮示例<view class="int-box"><text>文件上传:</text><view class="int-right"><text ref="input" @click="upload">请选择</text> //关键<image src="../static/right.png"></image></view></view>
调用方法
upload(){const _this = thisuni.showActionSheet({itemList: ['文件', '图片', '视频'],success: function (res) {if(res.tapIndex == 0){_this.upFile()}else if(res.tapIndex == 1){_this.chooseImages()}else if(res.tapIndex == 2){_this.chooseVideo()}else{_this.$api.msg('出错了')}},fail: function (res) {console.log(res.errMsg);}});}
设计样式
封装统一的接口
思路
文件上传过程中,会显示上传进度条
uploadFile(file, formData){var _this = this;let xhr = new XMLHttpRequest();xhr.open('POST', '/upload', true)xhr.setRequestHeader('Authorization', _this.token)xhr.upload.addEventListener("progress", function(event) {if (event.lengthComputable) {let percent = Math.ceil(event.loaded * 100 / event.total) + "%";uni.showLoading({title:`努力上传中..${percent}`})}}, false);xhr.ontimeout = function() {// xhr请求超时事件处理_this.$api.msg('请求超时')};xhr.onreadystatechange = () => {if (xhr.readyState == 4) {console.log('status:' + xhr.status);if (xhr.status == 200) {//xhr文件上传成功const response = JSON.parse(xhr.responseText);_this.resource = {name: file.name,url: response.data}_this.$api.msg('上传成功')} else if(xhr.status == 413){_this.$api.msg('文件太大')} else {_this.$api.msg('上传失败')}}setTimeout(function () {uni.hideLoading();}, 1000);};xhr.send(formData);}
上传图片
// 上传图片chooseImages(){const _this = thisuni.chooseImage({count: 1, //默认9sourceType: ['album','camera'], //从相册选择success:(res)=> {uni.showLoading({title: '上传图片中...'});console.log('上传图片', res)res.tempFilePaths.forEach(item => {let formData = new FormData()formData.append('file', res.tempFiles[0])_this.uploadFile(res.tempFiles[0], formData)})},});}
上传视频
chooseVideo(){const _this = thisuni.chooseVideo({count: 1,sourceType: ['camera', 'album'],success:(res)=> {let formData = new FormData()formData.append('file', res.tempFile)_this.uploadFile(res, formData)},});}
上传文件(重点)
思路
选择“文件”按钮以后,创建一个类型为file的input,并设置自动点击,让用户选择上传文件。
upFile() {var _this = this;let Input=document.createElement('input');//js生成接收文件的DOMInput.type="file";Input.click()Input.onchange = (event) => {const file = Input.files[0]let formData = new FormData();formData.append('file', file);_this.uploadFile(file, formData)}}
封装的提示框组件**
api.msg = params => uni.showToast({icon:'none',title: params,duration: 2000})
