H5使用微信JSSDK的wx.chooseImage进行多文件上传

2 篇文章 0 订阅
1 篇文章 0 订阅

背景:项目需要用H5做一个上传多图片合成的功能页面,这里我先做了调查,调查结果是安卓在微信内核不能使用传统的input file进行多文件上传,只能限制每次上传一张,ios则不限制,所以H5想在微信内核进行多图片上传就采用微信JSSDK进行功能实现多图片上传

 大概的思路逻辑是这样的:

1.引用jssdk的api即wx.chooseImage进行多图片上,上传得到的“localIds”安卓可以直接作为img标签显示,ios要通过wx.getLocalImgData传入“localIds”得到base64图片直接在本地显示

2.通过wx.chooseImage上传得到的“locallds"再调用wx.uploadImage得到serverId,然后再把serverId给到后台就可以拿到图片文件了

这里先记录一下这个项目踩过的坑,望周知

1.前端开发这里后台需要我拿到用户上传的照片的文件流,我查看了文档起初没有看到哪个方法可以拿到文件流,查看了一下资料看到了另外一个方法就是通过 wx.getLocalImgData前端可以拿到base64,然后再转成文件流给到后台同学,具体代码如下:

//先通过微信jssdk的api拿到了base64
wxgetLocalImgData(localIds) {
      let _this = this
      var i = 0
      var length = localIds.length
      var upload = function () {
        wx.getLocalImgData({
          localId: localIds[i], // 图片的localID
          success: function (res) {
            let localData = res.localData // localData是图片的base64数据,可以用img标签显示
            localData = localData.replace('jgp', 'jpeg')
            if (localData.indexOf('data:image') != 0) {
              //判断是否有这样的头部,因为安卓返回的是没有带头部的,所以要判断给它加上
              localData = 'data:image/jpeg;base64,' + localData
            }
            localData = localData.replace(/\r|\n/g, '').replace('data:image/jgp', 'data:image/jpeg') // 此处的localData 就是你所需要的base64 
              _this.localIdImgs.push(localData)
            if (_this.localIdImgs.length >= length) {
              alert('_this.localIdImgs.length+' + _this.localIdImgs.length)
                _this.getBase(_this.localIdImgs) //这里就可以拿到所有的base64传给逻辑函数了
              }
            i++  //因为多图片上传采用了这个方法
            i < length && upload()
          }
        })
      }
      upload()
    },

/* 微信sdk上传图片获取base64的处理逻辑 */
    getBase(base) {
      let _this = this
      var formData = new FormData()
      const photoName = `${new Date().getTime()}`
      base.forEach(element => {
        let initData = element.replace(/%0A|\s/g, '')
      //这里的base64ToFile就是base64转文件流的方法
        let p = _this.base64ToFile(initData, `${photoName}.jpg`)  
        formData.append('file', p)
      })
     //这个是后台的上传接口,前端把用户上传的文件流给到后台同学
      uploadImageFile(formData)
        .then(res => {
          console.log('res', res)
          alert('有进请求接口')
          if (res.code == '0000' && res.data) {
            console.log('上传成功了呢')
          } else {
            _this.$toast('上传失败')
          }
        })
        .catch(e => {
        
          alert('报错')
        })
    },

  /* base64转文件流方法 */
    base64ToFile(urlData, fileName) {
      let myPromise2 = new Promise((resolve, reject) => {
        let arr = urlData.split(',')
        let mime = arr[0].match(/:(.*?);/)[1]
        let bytes = atob(arr[1]) // 解码base64
        let n = bytes.length
        let ia = new Uint8Array(n)
        while (n--) {
          ia[n] = bytes.charCodeAt(n)
        }
        let files = new File([ia], fileName, { type: mime })
        // return new File([ia], fileName, { type: mime })
        resolve(files)
      })

      myPromise2.then(res => {
        alert('转换成功')
        return res
      })
      myPromise2.catch(err => {
        alert('请重新选择图片')
        reject('err')
      })
    },

 

2.这里一切都以为可以把用户上传的文件流给到后台接口同学了,但是经测试噩耗出现了,我在手机页面打印了每次请求到的base64,安卓和ios都打印出来在页面span标签显示(因为console打印本地调试看不到,微信的jssdk测试每次只能在https环境下测试,也就是线上地址,这我很烦!)测试发现安卓图片像素2M以下的图片转成的base64都可以正常在页面回显,也可以正常的转为文件流,但是大于2M的图片,页面的Img标签不显示了,把base64拷贝去工具转图片也发现图片是裂开的,显示不了,网上资料说图片像素越清晰返回的base64压缩的越严重导致图片打不开,文件流也转不了,ios还正常点,好像是10M以内可以回显和转换,所以到这里就打消了我原来用用户上传的base64转成文件流给到后端的方法了,只能改用另外一种方案,请听我细讲:

现在我急切的就是想拿到用户上传的文件流,又去看了一下官方文档,如下:

前端可以拿到这个media_id给后台接口,这里我要说明一下这里的意思:

它的备注写了可以用微信多媒体接口,这里的多媒体接口就是“获取临时素材”接口的意思

https://api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID1.前端可以通过这个接口get请求就可以直接拿到用户上传的文件流地址了,这里需要上传两个参数,一个是access_token,这个token一般是后台鉴权的令牌,可以找到后台同学拿,第二个media_id,就是上面wx.uploadImage拿到的serverId即media_id

2.上面是通过前端直接请求得到文件地址,但是access_token一般由后台保管不传给前端,这会后台可以封装https://api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID 这个接口,然后重新写个接口给前端,前端只需要每次把用户上传的serverId给到后台接口就可以了

好了,入坑的废话有点多了,接下来下面贴一下我正确请求的一个思路

=========================================================================

 

<template>
  <div>
    <button @click="onClickUp">测试</button>
   
  </div>
</template>
import wx from 'jweixin-1.6.0'  //引用微信sdk
import base from '@/utils/base.js'
import { getConfig } from '@/api/home'
export default {
  data() {
    return {
      kk: [],
      localIdImgs: [],
      localData: [],
      serverId: [],

    }
methods: {

getUrlconfig() {
      const browser = base.browser()  //这个方法就是判断是否是微信内核流浪器的,你们可以自己写一个方法判断
      // 微信分享提示
      if (browser.weixin || browser.qq || browser.yixin) {
        let signLink = ''
        let linkStatu = this.isIosOrAndroid() //判断安卓还是ios

        if (linkStatu === 'android') {
          signLink = location.href.split('#')[0]
        } else {
          signLink = window.initUrl
        }
        //请求微信sdk的当前页面url
        let params = {}
        params.url = signLink
        //请求微信sdk
        this.wxChatShare(params) //这个方法就是请求微信配置的,直接把参数带过就可以了
        return
      }
    },

wxChatShare(param) {
      //这里的param参数在需要的页面写好,然后代入到这里来就可以了
      // let _url = encodeURIComponent(param.url) // 当前页面的url
      let _url = param.url // 当前页面的url
      let data = {}
      data.sUrl = _url
      getConfig(data) // getConfig是获取微信配置相关信息的接口,此处根据个人项目写法而定
        .then(res => {
          if (res.code === '0000' && res.data) {
            console.log('res请求成功config', res)
            // alert('成功')
            let list = res.data
            let self = this
            // 接口返回配置信息
            wx.config({
              debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
              appId: 'wx0******ea5', // 必填,公众号的唯一标识
              timestamp: list.timeStamp, // 必填,生成签名的时间戳
              nonceStr: list.nonceStr, // 必填,生成签名的随机串
              signature: list.signature, // 必填,签名
              jsApiList: [
                // 用的方法都要加进来
                'chooseImage',
                'uploadImage',
                'downloadImage',
                'getLocalImgData'
              ]
            })
            wx.checkJsApi({
              jsApiList: ['chooseImage', 'uploadImage', 'downloadImage', 'getLocalImgData'], // 需要检测的JS接口列表,所有JS接口列表见附录2,
              success: function (res) {
                // 以键值对的形式返回,可用的api值true,不可用为false
                // 如:{"checkResult":{"chooseImage":true},"errMsg":"checkJsApi:ok"}
                console.log('检查', res)
                // alert(res.errMsg)
              }
            })
            wx.ready(function () {
         
            })
            wx.error(function (res) {
              console.log('验证失败返回的信息:', res)
            })
          } else {
            console.log('错误', res)
          }
        })
    },

     onClickUp() {
      let _this = this
      wx.chooseImage({
        count: 9, // 默认9
        sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
        sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
        success: function (res) {
          let localIds = res.localIds // 返回选定照片的本地ID列表,localId可以作为img标签的src属性显示图片
          // 判断 ios
          const browser = base.browser()
          let linkStatu = _this.isIosOrAndroid() //判断安卓还是ios

          _this.wxuploadImage(localIds)

        },
        fail: function (res) {
          console.log('失败')
        }
      })
    },
    
wxuploadImage(localIds) {
      let _this = this
      var i = 0
      var length = localIds.length
      var upload = function () {
        let loacId = localIds[i]
        let linkStatu = _this.isIosOrAndroid() //判断安卓还是ios
        if (!(linkStatu == 'android')) {
          if (loacId.indexOf('wxlocalresource') != -1) {
            loacId = loacId.replace('wxlocalresource', 'wxLocalResource')
          }
        }
        wx.uploadImage({
          localId: loacId, // 需要上传的图片的本地ID,由chooseImage接口获得
          isShowProgressTips: 1, // 默认为1,显示进度提示
          success: function (res) {
            _this.serverId.push(res.serverId)  //这里就可以拿到用户上传的所有图片serverId
             if (_this.serverId.length >= length) {
                alert('_this.serverId.length+' + _this.serverId.length)
                _this.sendMediaid(_this.serverId)   //这个方法就是可以把拿到的服务id给到后台接口拿图片文件
              }
            i++
            i < length && upload()
          },
          fail: function (error) {}
        })
      }
      upload()
    },
    
/* 微信sdk拿到图片服务id给后台接口 */
    sendMediaid(serverId) {
      alert("id++" + serverId) // 如果多图片上传,这里是一个数组里面包含多个服务id,看后台想怎么处理把服务id给到后台同学
      let data = {
        mediaId:serverId
      }
   //把服务id给到后台接口
      uploadImageFile(data)  
        .then(res => {
          console.log('res', res)
          alert('有进请求接口')
          if (res.code == '0000' && res.data) {
            console.log('上传成功了呢')
           
          } else {
         
             console.log('上传失败')
          }
        })
        .catch(e => {
        
          alert('报错')
        })
    },
    

  }
  
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值