需求:由于后台服务器各方面的限制,现在服务器返回的图片是base64格式的,小程序端需要支持预览图片和多个图片一键下载功能
一、如何预览base64位图片?
WXML页面:item.src的值是base64编码的字符串
<block wx:for="{{imgsLength}}" wx:key="index">
<image mode="widthFix" bindtap="preImg" src="data:image/png;base64,{{item.src}}" data-src="{{item.src}}"></image>
</block>
JS: 由于ios13和微信7.0.12匹配有问题,导致预览图片的时候使得微信闪退
// 图片预览 preImg(e) { let that = this if (that.data.system != '') { let system = that.data.system.substring(0, 3) console.log('system: ', system.toLowerCase()) if (system.toLowerCase() == 'ios') { console.log('当前系统不支持预览') } else { let url = 'data:image/png;base64,' + e.currentTarget.dataset.src wx.previewImage({ current: url, // 当前显示图片的http链接 urls: [url] // 需要预览的图片http链接列表 }) } } },
二、一键下载多张base64位的图片?
需求:(1)由于后台服务器的限制,现只能一张一张请求图片,且每隔1s请求一次接口,每张图片总共请求60次。(2)如果图片请求到则展示图片,如果请求不到,则在页面显示占位图片,且点击该图片需重新发送请求该图片的接口。
步骤一:页面加载开始就请求第一张图片,当第一张图片返回后或者请求次数已达上限,则请求下一张。
// 请求图片 getImgsList() { let that = this let token = that.data.scanToken let iData = { currentNumber: that.data.currentPage } var i = 0 let handerRequest = setInterval(function() { // 发送请求 i++; util.request(api.DownloadImgsList, iData, 'POST', token).then(function(res) { if (i === 60) { clearInterval(handerRequest) let number = that.data.currentPage - 1 console.log('失败图片是第' + number + '页') that.setData({ ['imgsLength[' + number + '].requestNum']: i, }) // 查询下一个 that.getNextImg() } if (res.data.code === 0) { clearInterval(handerRequest) if (!that.data.totalNumber && res.data.data.totalNumber) { console.log('图片总数----', res.data.data.totalNumber) log.info('图片总数----', res.data.data.totalNumber) that.setData({ totalNumber: res.data.data.totalNumber, // 图片总数 }) // 图片占位数组 let imgsLength = new Array(res.data.data.totalNumber).fill({ 'src': '', 'number': '', 'requestNum': '' }) that.setData({ imgsLength: imgsLength, }) } if (res.data.data.currentNumber && res.data.data.file) { let imgsArr = [] imgsArr.push({ 'src': res.data.data.file, 'number': res.data.data.currentNumber }) that.setData({ imgs: that.reduce(that.data.imgs.concat(imgsArr).sort(that.arraySort('number')), 'number'), }) that.data.imgsLength.find((item, index) => { if ((index + 1) == res.data.data.currentNumber) { let num = index that.setData({ ['imgsLength[' + index + '].src']: res.data.data.file, ['imgsLength[' + index + '].number']: res.data.data.currentNumber, }) } }) } // 查询下一个 that.getNextImg() } else if (res.data.code === 59706) { console.log('getImgs res: ', res) clearInterval(handerRequest) wx.showToast({ icon: 'none', title: 'token失效,请重新扫码', }) } else { console.log('请求图片错误', res) } }).catch(err => { if (i === 60) { clearInterval(handerRequest) let number = that.data.currentPage - 1 that.setData({ ['imgsLength[' + number + '].requestNum']: i, }) // 查询下一个 that.getNextImg() } console.log("请求图片err:", err); }); }, 1000) }, // 获取下一个图片 getNextImg() { let that = this if (that.data.currentPage + 1 <= that.data.totalNumber) { that.setData({ currentPage: that.data.currentPage + 1 }) that.getImgsList() } else { console.log('没有更多图片') } },
注意:由于异步可能会使得返回的图片有重复的或者不是按照请求的顺序返回的,因此需要对图片进行去重和排序
// 图片去重 reduce(arr, name) { var hash = {} return arr.reduce(function(item, next) { hash[next[name]] ? '' : hash[next[name]] = true && item.push(next); return item; }, []) }, // 图片排序 arraySort(field) { return function(obj1, obj2) { let a = obj1[field] let b = obj2[field] return a - b } },
如何重新加载之前失败的图片:
// 重新加载 loadAgain (e) { let that = this; let number = e.currentTarget.dataset.index // 点击重新加载当前图片 let token = that.data.scanToken let iData = { currentNumber: number + 1 } var i = 0 let handerRequest = setInterval(function () { // 发送请求 i++; util.request(api.DownloadImgsList, iData, 'POST', token).then(function (res) { if (i === 60) { clearInterval(handerRequest) } if (res.data.code === 0) { clearInterval(handerRequest) if (res.data.data.currentNumber && res.data.data.file) { let imgsArr = [] imgsArr.push({ 'src': res.data.data.file, 'number': res.data.data.currentNumber }) that.setData({ ['imgsLength[' + number + '].src']: res.data.data.file, ['imgsLength[' + number + '].number']: res.data.data.currentNumber, imgs: that.reduce(that.data.imgs.concat(imgsArr).sort(that.arraySort('number')), 'number'), totalNumber: res.data.data.totalNumber, // 图片总数 }) } } else if (res.data.code === 59706) { console.log('loadAgain res: ', res) clearInterval(handerRequest) wx.showToast({ icon: 'none', title: 'token失效,请重新扫码', }) } else { console.log('请求图片错误', res) } }).catch(err => { if (i === 60) { clearInterval(handerRequest) } console.log("请求图片err:", err); }); }, 1000) },
步骤二:至此,需要下载的图片已经存进了imgs数组中。由于小程序无法直接将base64的图片直接保存到本地相册,因此需要先将文件写入本地,之后再进行保存到相册的操作。
1.由于微信小程序限制,小程序文件系统写入文件,大小最多是10m,在ios上测试的时候发现writeFile报错,为了规避这个问题,我在写入文件的时候会先清理之前的文件。 // 下载 download() { let that = this if (that.data.imgs.length > 0 && that.data.imgs.length == that.data.imgsLength.length) { // 先创建一个保存图片的本地文件目录 let fs = wx.getFileSystemManager() // 再判断takeAway目录是否存在,不存在则新建该目录 fs.access({ path: `${wx.env.USER_DATA_PATH}/takeAway`, success: res => { console.log('takeAway目录存在res:', res) log.info('takeAway目录存在res:', res) that.dow_temp(0) }, fail: err => { console.log('takeAway目录不存在:', err) log.info('takeAway目录不存在:', err) fs.mkdir({ dirPath: `${wx.env.USER_DATA_PATH}/takeAway`, success: res => { console.log('创建保存图片的本地文件路径成功', res) log.info('创建保存图片的本地文件路径成功', res) that.dow_temp(0) }, fail: err => { console.log('创建保存图片的本地文件路径失败', err) log.error('创建保存图片的本地文件路径失败', err) } }) } }) } else { wx.showToast({ icon: 'none', title: '图片还未完全加载完毕,请稍后再试!', duration: 3000 }) } }, //下载单个内容 dow_temp: function(i, callback) { let that = this var fs = wx.getFileSystemManager() // 先删除之前takeAway目录下的文件 return new Promise((resolve) => { fs.readdir({ dirPath: `${wx.env.USER_DATA_PATH}/takeAway`, success(res) { res.files.forEach((el) => { fs.unlink({ filePath: `${wx.env.USER_DATA_PATH}/takeAway/${el}`, fail(e) { console.log('readdir文件删除失败:', e) } }) }) resolve(that.saveImgFile(i, callback)) } }) }) },
步骤三:图片保存
// 图片保存 saveImgFile: function(i, callback) { let that = this let data = that.data.imgs let all_n = data.length if (i < all_n) { wx.authorize({ scope: 'scope.writePhotosAlbum', success() { var fs = wx.getFileSystemManager(); var number = Math.random(); const downloadTask = fs.writeFile({ filePath: `${wx.env.USER_DATA_PATH}/takeAway/${number}.png`, data: data[i].src, encoding: 'base64', success: res => { wx.saveImageToPhotosAlbum({ filePath: `${wx.env.USER_DATA_PATH}/takeAway/${number}.png`, success: function(res) { wx.showToast({ icon: 'none', title: `第${i + 1}/${all_n}张保存到系统相册`, }) that.dow_temp(i + 1); }, fail: function(err) { console.info('第', (i + 1), '张保存失败'); } }) }, fail: err => { wx.showToast({ title: '一键保存失败,请点击图片手动保存!', icon: 'none', }) } }) }, fail: function() { wx.showToast({ title: '获取授权失败', icon: 'none', }) } }) } },