需要解决的问题

微信浏览器打开h5网页,项目要求选择上传文件的时候,能上传图片、视频、文件(.zip, .rar, .docx等),并兼容Android和ios。

注意

  • uni.uploadFile只支持image、video、audio三种文件格式

image.png
所以上传文件(.zip, .rar, .docx等)只能自定义,上传图片和视频可以采取uniapp自带的方法

  • uni.request传入FormData会报错
    1. fail parameter `data`. Expected Object, String, Array, ArrayBuffer, got FormData

官方文档表示它只支持Object/String/ArrayBuffer三种类型的data
image.png
那就只能采取原生的XMLHttpRequest去做了。

  • 本来想着既然如此,那索性就统一接口,所有文件都通过自定义input(type=”file”)的方法上传,但是在ios测试的时候,发现当调起图片和视频的时候,并不能拿到相应的数据,那就先分开来写三个不同的方法上传,分别是上传文件(自定义input)、图片(uni.chooseImage)和视频(uni.chooseVideo)

    可选择上传方式

    思路

    当用户点击“选择文件”按钮的时候,跳出三个选项,分别调用不同的上传方法
    按钮示例

    1. <view class="int-box">
    2. <text>文件上传:</text>
    3. <view class="int-right">
    4. <text ref="input" @click="upload">请选择</text> //关键
    5. <image src="../static/right.png"></image>
    6. </view>
    7. </view>

    调用方法

    1. upload(){
    2. const _this = this
    3. uni.showActionSheet({
    4. itemList: ['文件', '图片', '视频'],
    5. success: function (res) {
    6. if(res.tapIndex == 0){
    7. _this.upFile()
    8. }else if(res.tapIndex == 1){
    9. _this.chooseImages()
    10. }else if(res.tapIndex == 2){
    11. _this.chooseVideo()
    12. }else{
    13. _this.$api.msg('出错了')
    14. }
    15. },
    16. fail: function (res) {
    17. console.log(res.errMsg);
    18. }
    19. });
    20. }

    设计样式

    image.png

    封装统一的接口

    思路

    文件上传过程中,会显示上传进度条

    1. uploadFile(file, formData){
    2. var _this = this;
    3. let xhr = new XMLHttpRequest();
    4. xhr.open('POST', '/upload', true)
    5. xhr.setRequestHeader('Authorization', _this.token)
    6. xhr.upload.addEventListener("progress", function(event) {
    7. if (event.lengthComputable) {
    8. let percent = Math.ceil(event.loaded * 100 / event.total) + "%";
    9. uni.showLoading({
    10. title:`努力上传中..${percent}`
    11. })
    12. }
    13. }, false);
    14. xhr.ontimeout = function() {
    15. // xhr请求超时事件处理
    16. _this.$api.msg('请求超时')
    17. };
    18. xhr.onreadystatechange = () => {
    19. if (xhr.readyState == 4) {
    20. console.log('status:' + xhr.status);
    21. if (xhr.status == 200) {
    22. //xhr文件上传成功
    23. const response = JSON.parse(xhr.responseText);
    24. _this.resource = {
    25. name: file.name,
    26. url: response.data
    27. }
    28. _this.$api.msg('上传成功')
    29. } else if(xhr.status == 413){
    30. _this.$api.msg('文件太大')
    31. } else {
    32. _this.$api.msg('上传失败')
    33. }
    34. }
    35. setTimeout(function () {
    36. uni.hideLoading();
    37. }, 1000);
    38. };
    39. xhr.send(formData);
    40. }

    上传图片

    1. // 上传图片
    2. chooseImages(){
    3. const _this = this
    4. uni.chooseImage({
    5. count: 1, //默认9
    6. sourceType: ['album','camera'], //从相册选择
    7. success:(res)=> {
    8. uni.showLoading({
    9. title: '上传图片中...'
    10. });
    11. console.log('上传图片', res)
    12. res.tempFilePaths.forEach(item => {
    13. let formData = new FormData()
    14. formData.append('file', res.tempFiles[0])
    15. _this.uploadFile(res.tempFiles[0], formData)
    16. })
    17. },
    18. });
    19. }

    上传视频

    1. chooseVideo(){
    2. const _this = this
    3. uni.chooseVideo({
    4. count: 1,
    5. sourceType: ['camera', 'album'],
    6. success:(res)=> {
    7. let formData = new FormData()
    8. formData.append('file', res.tempFile)
    9. _this.uploadFile(res, formData)
    10. },
    11. });
    12. }

    上传文件(重点)

    思路

    选择“文件”按钮以后,创建一个类型为file的input,并设置自动点击,让用户选择上传文件。

    1. upFile() {
    2. var _this = this;
    3. let Input=document.createElement('input');//js生成接收文件的DOM
    4. Input.type="file";
    5. Input.click()
    6. Input.onchange = (event) => {
    7. const file = Input.files[0]
    8. let formData = new FormData();
    9. formData.append('file', file);
    10. _this.uploadFile(file, formData)
    11. }
    12. }

    封装的提示框组件**

    1. api.msg = params => uni.showToast({
    2. icon:'none',
    3. title: params,
    4. duration: 2000
    5. })