javascript
H5使用微信JSSDK的wx.chooseImage进行多文件上传
背景:項(xiàng)目需要用H5做一個(gè)上傳多圖片合成的功能頁(yè)面,這里我先做了調(diào)查,調(diào)查結(jié)果是安卓在微信內(nèi)核不能使用傳統(tǒng)的input file進(jìn)行多文件上傳,只能限制每次上傳一張,ios則不限制,所以H5想在微信內(nèi)核進(jìn)行多圖片上傳就采用微信JSSDK進(jìn)行功能實(shí)現(xiàn)多圖片上傳
?大概的思路邏輯是這樣的:
1.引用jssdk的api即wx.chooseImage進(jìn)行多圖片上,上傳得到的“l(fā)ocalIds”安卓可以直接作為img標(biāo)簽顯示,ios要通過(guò)wx.getLocalImgData傳入“l(fā)ocalIds”得到base64圖片直接在本地顯示
2.通過(guò)wx.chooseImage上傳得到的“l(fā)ocallds"再調(diào)用wx.uploadImage得到serverId,然后再把serverId給到后臺(tái)就可以拿到圖片文件了
這里先記錄一下這個(gè)項(xiàng)目踩過(guò)的坑,望周知:
1.前端開(kāi)發(fā)這里后臺(tái)需要我拿到用戶上傳的照片的文件流,我查看了文檔起初沒(méi)有看到哪個(gè)方法可以拿到文件流,查看了一下資料看到了另外一個(gè)方法就是通過(guò)?wx.getLocalImgData前端可以拿到base64,然后再轉(zhuǎn)成文件流給到后臺(tái)同學(xué),具體代碼如下:
//先通過(guò)微信jssdk的api拿到了base64 wxgetLocalImgData(localIds) {let _this = thisvar i = 0var length = localIds.lengthvar upload = function () {wx.getLocalImgData({localId: localIds[i], // 圖片的localIDsuccess: function (res) {let localData = res.localData // localData是圖片的base64數(shù)據(jù),可以用img標(biāo)簽顯示localData = localData.replace('jgp', 'jpeg')if (localData.indexOf('data:image') != 0) {//判斷是否有這樣的頭部,因?yàn)榘沧糠祷氐氖菦](méi)有帶頭部的,所以要判斷給它加上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傳給邏輯函數(shù)了}i++ //因?yàn)槎鄨D片上傳采用了這個(gè)方法i < length && upload()}})}upload()},/* 微信sdk上傳圖片獲取base64的處理邏輯 */getBase(base) {let _this = thisvar formData = new FormData()const photoName = `${new Date().getTime()}`base.forEach(element => {let initData = element.replace(/%0A|\s/g, '')//這里的base64ToFile就是base64轉(zhuǎn)文件流的方法let p = _this.base64ToFile(initData, `${photoName}.jpg`) formData.append('file', p)})//這個(gè)是后臺(tái)的上傳接口,前端把用戶上傳的文件流給到后臺(tái)同學(xué)uploadImageFile(formData).then(res => {console.log('res', res)alert('有進(jìn)請(qǐng)求接口')if (res.code == '0000' && res.data) {console.log('上傳成功了呢')} else {_this.$toast('上傳失敗')}}).catch(e => {alert('報(bào)錯(cuò)')})},/* base64轉(zhuǎn)文件流方法 */base64ToFile(urlData, fileName) {let myPromise2 = new Promise((resolve, reject) => {let arr = urlData.split(',')let mime = arr[0].match(/:(.*?);/)[1]let bytes = atob(arr[1]) // 解碼base64let n = bytes.lengthlet 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('轉(zhuǎn)換成功')return res})myPromise2.catch(err => {alert('請(qǐng)重新選擇圖片')reject('err')})},2.這里一切都以為可以把用戶上傳的文件流給到后臺(tái)接口同學(xué)了,但是經(jīng)測(cè)試噩耗出現(xiàn)了,我在手機(jī)頁(yè)面打印了每次請(qǐng)求到的base64,安卓和ios都打印出來(lái)在頁(yè)面span標(biāo)簽顯示(因?yàn)閏onsole打印本地調(diào)試看不到,微信的jssdk測(cè)試每次只能在https環(huán)境下測(cè)試,也就是線上地址,這我很煩!)測(cè)試發(fā)現(xiàn)安卓圖片像素2M以下的圖片轉(zhuǎn)成的base64都可以正常在頁(yè)面回顯,也可以正常的轉(zhuǎn)為文件流,但是大于2M的圖片,頁(yè)面的Img標(biāo)簽不顯示了,把base64拷貝去工具轉(zhuǎn)圖片也發(fā)現(xiàn)圖片是裂開(kāi)的,顯示不了,網(wǎng)上資料說(shuō)圖片像素越清晰返回的base64壓縮的越嚴(yán)重導(dǎo)致圖片打不開(kāi),文件流也轉(zhuǎn)不了,ios還正常點(diǎn),好像是10M以內(nèi)可以回顯和轉(zhuǎn)換,所以到這里就打消了我原來(lái)用用戶上傳的base64轉(zhuǎn)成文件流給到后端的方法了,只能改用另外一種方案,請(qǐng)聽(tīng)我細(xì)講:
現(xiàn)在我急切的就是想拿到用戶上傳的文件流,又去看了一下官方文檔,如下:
前端可以拿到這個(gè)media_id給后臺(tái)接口,這里我要說(shuō)明一下這里的意思:
它的備注寫(xiě)了可以用微信多媒體接口,這里的多媒體接口就是“獲取臨時(shí)素材”接口的意思
https://api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID1.前端可以通過(guò)這個(gè)接口get請(qǐng)求就可以直接拿到用戶上傳的文件流地址了,這里需要上傳兩個(gè)參數(shù),一個(gè)是access_token,這個(gè)token一般是后臺(tái)鑒權(quán)的令牌,可以找到后臺(tái)同學(xué)拿,第二個(gè)media_id,就是上面wx.uploadImage拿到的serverId即media_id
2.上面是通過(guò)前端直接請(qǐng)求得到文件地址,但是access_token一般由后臺(tái)保管不傳給前端,這會(huì)后臺(tái)可以封裝https://api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID 這個(gè)接口,然后重新寫(xiě)個(gè)接口給前端,前端只需要每次把用戶上傳的serverId給到后臺(tái)接口就可以了
好了,入坑的廢話有點(diǎn)多了,接下來(lái)下面貼一下我正確請(qǐng)求的一個(gè)思路
=========================================================================
?
<template><div><button @click="onClickUp">測(cè)試</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() //這個(gè)方法就是判斷是否是微信內(nèi)核流浪器的,你們可以自己寫(xiě)一個(gè)方法判斷// 微信分享提示if (browser.weixin || browser.qq || browser.yixin) {let signLink = ''let linkStatu = this.isIosOrAndroid() //判斷安卓還是iosif (linkStatu === 'android') {signLink = location.href.split('#')[0]} else {signLink = window.initUrl}//請(qǐng)求微信sdk的當(dāng)前頁(yè)面urllet params = {}params.url = signLink//請(qǐng)求微信sdkthis.wxChatShare(params) //這個(gè)方法就是請(qǐng)求微信配置的,直接把參數(shù)帶過(guò)就可以了return}},wxChatShare(param) {//這里的param參數(shù)在需要的頁(yè)面寫(xiě)好,然后代入到這里來(lái)就可以了// let _url = encodeURIComponent(param.url) // 當(dāng)前頁(yè)面的urllet _url = param.url // 當(dāng)前頁(yè)面的urllet data = {}data.sUrl = _urlgetConfig(data) // getConfig是獲取微信配置相關(guān)信息的接口,此處根據(jù)個(gè)人項(xiàng)目寫(xiě)法而定.then(res => {if (res.code === '0000' && res.data) {console.log('res請(qǐng)求成功config', res)// alert('成功')let list = res.datalet self = this// 接口返回配置信息wx.config({debug: false, // 開(kāi)啟調(diào)試模式,調(diào)用的所有api的返回值會(huì)在客戶端alert出來(lái),若要查看傳入的參數(shù),可以在pc端打開(kāi),參數(shù)信息會(huì)通過(guò)log打出,僅在pc端時(shí)才會(huì)打印。appId: 'wx0******ea5', // 必填,公眾號(hào)的唯一標(biāo)識(shí)timestamp: list.timeStamp, // 必填,生成簽名的時(shí)間戳nonceStr: list.nonceStr, // 必填,生成簽名的隨機(jī)串signature: list.signature, // 必填,簽名jsApiList: [// 用的方法都要加進(jìn)來(lái)'chooseImage','uploadImage','downloadImage','getLocalImgData']})wx.checkJsApi({jsApiList: ['chooseImage', 'uploadImage', 'downloadImage', 'getLocalImgData'], // 需要檢測(cè)的JS接口列表,所有JS接口列表見(jiàn)附錄2,success: function (res) {// 以鍵值對(duì)的形式返回,可用的api值true,不可用為false// 如:{"checkResult":{"chooseImage":true},"errMsg":"checkJsApi:ok"}console.log('檢查', res)// alert(res.errMsg)}})wx.ready(function () {})wx.error(function (res) {console.log('驗(yàn)證失敗返回的信息:', res)})} else {console.log('錯(cuò)誤', res)}})},onClickUp() {let _this = thiswx.chooseImage({count: 9, // 默認(rèn)9sizeType: ['original', 'compressed'], // 可以指定是原圖還是壓縮圖,默認(rèn)二者都有sourceType: ['album', 'camera'], // 可以指定來(lái)源是相冊(cè)還是相機(jī),默認(rèn)二者都有success: function (res) {let localIds = res.localIds // 返回選定照片的本地ID列表,localId可以作為img標(biāo)簽的src屬性顯示圖片// 判斷 iosconst browser = base.browser()let linkStatu = _this.isIosOrAndroid() //判斷安卓還是ios_this.wxuploadImage(localIds)},fail: function (res) {console.log('失敗')}})},wxuploadImage(localIds) {let _this = thisvar i = 0var length = localIds.lengthvar upload = function () {let loacId = localIds[i]let linkStatu = _this.isIosOrAndroid() //判斷安卓還是iosif (!(linkStatu == 'android')) {if (loacId.indexOf('wxlocalresource') != -1) {loacId = loacId.replace('wxlocalresource', 'wxLocalResource')}}wx.uploadImage({localId: loacId, // 需要上傳的圖片的本地ID,由chooseImage接口獲得isShowProgressTips: 1, // 默認(rèn)為1,顯示進(jìn)度提示success: function (res) {_this.serverId.push(res.serverId) //這里就可以拿到用戶上傳的所有圖片serverIdif (_this.serverId.length >= length) {alert('_this.serverId.length+' + _this.serverId.length)_this.sendMediaid(_this.serverId) //這個(gè)方法就是可以把拿到的服務(wù)id給到后臺(tái)接口拿圖片文件}i++i < length && upload()},fail: function (error) {}})}upload()},/* 微信sdk拿到圖片服務(wù)id給后臺(tái)接口 */sendMediaid(serverId) {alert("id++" + serverId) // 如果多圖片上傳,這里是一個(gè)數(shù)組里面包含多個(gè)服務(wù)id,看后臺(tái)想怎么處理把服務(wù)id給到后臺(tái)同學(xué)let data = {mediaId:serverId}//把服務(wù)id給到后臺(tái)接口uploadImageFile(data) .then(res => {console.log('res', res)alert('有進(jìn)請(qǐng)求接口')if (res.code == '0000' && res.data) {console.log('上傳成功了呢')} else {console.log('上傳失敗')}}).catch(e => {alert('報(bào)錯(cuò)')})},}}總結(jié)
以上是生活随笔為你收集整理的H5使用微信JSSDK的wx.chooseImage进行多文件上传的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 2017年全国大学生数学建模竞赛——A题
- 下一篇: php建模(php_uml) 和 Ent