需求:由于后台服务器各方面的限制,现在服务器返回的图片是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',
})
}
})
}
},

微信小程序之base64图片如何预览与一键保存到本地相册?的更多相关文章

  1. 微信小程序点击图片放大预览

    微信小程序点击图片放大预览使用到 wx.previewImage 接口,可以放大.上/下一张 上代码 wxml代码 <view class='content-img' wx:if="{ ...

  2. 微信小程序实战篇-图片的预览、二维码的识别

    开篇 今天,做的小程序项目要求,个人中心的客服图片在用户长按时可以识别其二维码,各种翻阅查找,采坑很多,浪费了很多时间,在这里记录下需要注意的点,以及对小程序官方提供的API做一个正确和清晰的认知,希 ...

  3. 微信小程序开发之真机预览

    1:真机预览时上传组件的坑: 当在真机里面使用上传组件,当进入选择相片或者拍照的时候,小程序会进入后台,调用APP onHide()方法,选择完返回小程序是会调用App Onshow()方法,然后调用 ...

  4. 微信小程序上传图片,视频及预览

    wxml <!-- 图片预览 --> <view class='preview-warp' wx:if="{{urls}}"> <image src= ...

  5. 微信小程序简单封装图片上传组件

    微信小程序简单封装图片上传组件 希望自己 "day day up" -----小陶 我从哪里来 在写小程序的时候需要上传图片,个人觉得官方提供的 Uploader 组件不是太好用, ...

  6. 微信小程序开发之图片预览

    实现图片的展示和大图预览 使用wx.previewImage(OBJECT)来实现 OBJECT参数说明: 参数 类型 必填 说明 current String 否 当前显示图片的链接,不填则默认为 ...

  7. 微信小程序——网盘图片预览

    微信小程序图片预览提供了一个wx.previewImage接口,如下图: 现在我需要对网盘文件里的图片预览,但是网盘从后台返回的数据是各种类型的文件,如下图所示: 那么我们需要解决2个问题: 1.从这 ...

  8. 微信小程序开发——base64位图片显示问题

    前言: 目前小程序项目需要后端借口提供验证码图片,后端是以base64位返回的,按照H5的做法,前边拼上 data:image/png;base64, 应该就可以了,关键代码如下: H5: <i ...

  9. 微信小程序——引入背景图片【六】

    前言 之前写了一些小程序的博文只是看文档边看边写,了解下他,这次可是真枪真刀的做了! 框架使用的是美团的mpvue,我也是一边学习,一边写的,如有错误之处,还望大家指出. 在这里我有个问题,为什么微信 ...

随机推荐

  1. Contest 157

    2019-10-06 12:15:28 总体感受:总体难度一般,dfs和dp题花了点时间,最后一题dp有思路,但是实现上不够好. 注意点:首先是hard问题的覆盖度依然是很大的问题,其次是要注意审题. ...

  2. 硬不硬你说了算!35 张图解被问千百遍的 TCP 三次握手和四次挥手面试题

    每日一句英语学习,每天进步一点点: 前言 不管面试 Java .C/C++.Python 等开发岗位, TCP 的知识点可以说是的必问的了. 任 TCP 虐我千百遍,我仍待 TCP 如初恋. 遥想小林 ...

  3. 什么情况下JVM内存中的一个对象会被垃圾回收?

    新生代满了会触发 Young GC,老年代满了会触发 Old GC.GC时会回收对象,那么具体是什么样的对象会被垃圾回收器回收呢? 可达性分析算法,判断是否被 GC Roots 引用 判断引用类型:强 ...

  4. [bzoj4472][树形DP] Salesman

    题目 原地址 解说 刚看完这道题感觉还是挺乱的,可能那时候脑子不太清醒,一度觉得自己又要重拾Tarjan了.当然最后还是发觉应该用树形DP. (以下dp[u]代表以u为根的包括自己在内的子树的最大利润 ...

  5. cento升级openssl依旧显示老版本

    不久前拿到了一季度的服务器漏洞扫描报告,还是一些老生常谈的软件.按照报告上的漏洞一个个处理,开始升级openssl的时候一切都很顺利,上传源码包,解压,编译,安装,全部都没有报错.opessl --v ...

  6. Ubuntu16.04下LAMP环境的安装与配置

    Ubuntu16.04下LAMP环境的安装与配置 最近做个实验需要用到Ubuntu环境的靶场,所以这里介绍下Ubuntu环境下LAMP的安装与配置,话不多说,我们gkd! 1.Apache2的安装 首 ...

  7. Unity引擎入门——制作第一个2D游戏(1)

    Unity作为当今最流行的游戏引擎之一,受到各大厂商的喜爱. 像是炉石传说,以及最近的逃离塔克夫,都是由unity引擎开发制作. 作为初学者的我们,虽然无法直接做出完成度那么高的作品,但每一个伟大的目 ...

  8. Activiti7新的API介绍

    一.Activiti7 的组成部分 Activiti Core 作为Activiti 的核心部分,Activiti Cloud 主要是利用云服务来实现分布式业务流程开发. 二.Activiti 新的 ...

  9. SpringCloud(三)之我学 Hystrix

    1.断路器 在消费服务的启动类,添加注解:@EnableCircuitBreaker,在消费服务的调用类上,添加注解:@HystrixCommand(fallbackMethod = "&q ...

  10. IIC驱动学习笔记,简单的TSC2007的IIC驱动编写,测试

    IIC驱动学习笔记,简单的TSC2007的IIC驱动编写,测试 目的不是为了编写TSC2007驱动,是为了学习IIC驱动的编写,读一下TSC2007的ADC数据进行练习,, Linux主机驱动和外设驱 ...