小程序之图片上传
不管是微信小程序还是支付宝小程序,上传图片的时候都只能单张上传,当遇到复杂的应用场景时,比如下面这种情况:
在一个页面中,有A、B、C三个模块,每个模块都可以选择多张图片,而且必须要在点击 上传图片 按钮之后才把图片上传给后台服务器,最后就是提交成功之后,可以再次进行编辑,就是说在已经上传过图片之后,还可以在已有图片的基础上进行图片添加,继续上传!
那么在做这个需求的时候我们会遇到几个问题:1.0:假如A模块选择了3张图片;B模块选择了4张图片;C模块选择了5张图片,一次性全部上传,怎么知道上传的这张图片是属于A、B还是C
2.0:假如上面1.0的问题解决了,图片上传成功,我需要进行第二次编辑,重新打开这个页面的时候会看到,A模块已经有3张图片,B模块已经有4张图片,C模块已经有5张图片,于是我删除了A模块的1张图片,删除了B模块的2张图片,删除了C模块的3张图片,然后重新给A模块选择了3张新图片,给B模块选择了4张新图片,给C模块选择了5张新图片,然后重新上传图片!这个时候要知道对应模块删除图片的位置,还需要知道对应模块,哪些图片是已经上传过的,不需要继续上传,哪些图片是新图片需要重新上传的!
带着上面两个问题,我们下面进行需求开发,以微信小程序为列:
1.0首先我们要进行前端页面结构的书写,为了考虑复用性,所以如下面:
页面结构样式
<template name='upLoadImg'> <view class='upLoadImg_photos'> <view class='upLoadImg_title'> <text>{{title}} </text> </view> <view class='upLoadImg_selectImgs'> <block wx:for="{{data}}" wx:key="{{index}}"> <view class="upLoadImg_box" data-index="{{index}}" data-type='{{type}}' bindtap='previewImage' > <image class='upLoadImg_missionImg' src='{{item}}'></image> <image class='upLoadImg_delImg' catchtap='delImg' src='/img/CRM/icon_del@2x.png' data-index="{{index}}" data-type='{{type}}'></image> </view> </block> <view bindtap='chooseImage' class='upLoadImg_chooseImage {{(data.length-1) % 4 == 0 ? "upLoadImg_chooseBox" : ""}}' data-type='{{type}}'>+</view> </view> </view> </template> <template is='upLoadImg' data='{{title:"A模块 ",data:a_img,type:"a_img"}}' /> <template is='upLoadImg' data='{{title:"B模块 ",data:b_img,type:"b_img"}}' /> <template is='upLoadImg' data='{{title:"C模块 ",data:c_img,type:"c_img"}}' /> <view class='taskButtom' bindtap='btnSave' >上传图片</view>
css样式
.upLoadImg_photos{ width:100%; padding:39rpx 30rpx 40rpx; box-sizing: border-box; border-bottom: 1rpx solid rgba(230, 230, 230, 1) } .upLoadImg_title{ font-size:28rpx; font-family:PingFangSC-Regular; font-weight:400; color:rgba(102,102,102,1); } .upLoadImg_title>text:last-child{ font-size: 26rpx; } .upLoadImg_selectImgs{ display: flex; flex-wrap:wrap; width: 100%; } .upLoadImg_box{ width:140rpx; height:140rpx; box-sizing: border-box; background-color: #fff; margin:39rpx 42rpx 0 0; text-align: center; border: 2rpx solid #f5f5f5; position: relative; border-radius:25rpx; } .upLoadImg_box:nth-of-type(4n),.upLoadImg_chooseBox{ margin:39rpx 0 0 !important; } .upLoadImg_missionImg{ width: 140rpx; height: 140rpx; } .upLoadImg_chooseImage{ width: 140rpx; height:140rpx; line-height: 130rpx; border: 2rpx dashed #E1E1E6; box-sizing: border-box; font-size: 50rpx; text-align: center; margin:39rpx 0 0; color: #E1E1E6; border-radius:25rpx; } .upLoadImg_delImg{ width: 30rpx; height: 30rpx; right:-15rpx; top:-15rpx; position: absolute; } .taskButtom{ text-align: center; line-height: 90rpx; width:648rpx; height:90rpx; background:linear-gradient(267deg,rgba(85,235,255,1) 0%,rgba(28,145,242,1) 100%); box-shadow:0px 5rpx 40rpx 0px rgba(0,155,223,0.2); border-radius:45rpx; margin:80rpx auto; font-size:34rpx; font-family:PingFangSC-Medium; font-weight:500; color:rgba(255,255,255,1); }
js处理逻辑
/** * 页面的初始数据 */ data: { a_img: [],//存放A模块图片url地址 b_img: [],//存放B模块图片url地址 c_img: [], //存放C模块图片url地址 a_imgId: [],//存放A模块图片上传获取的id b_imgId: [],//存放B模块图片上传获取的id c_imgId: [] //存放C模块图片上传获取的id }, /** * 选择图片 */ chooseImage(e) { const that = this let type = e.currentTarget.dataset.type wx.chooseImage({ count: 9, // 默认9 一次性最多可以选择图片张数 sizeType: ['original'], // 可以指定original:原图 compressed:压缩图 sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有 success: function (res) { console.log(res.tempFiles) let imgUrl = [] res.tempFiles.findIndex(function (value, index, arr) { imgUrl.push(value.path) }) let images = that.data[type].concat(...imgUrl) that.setData({ [type]: images, }) }, }) }, /** * 点击图片删除按钮删除图片 */ delImg: function (e) { const that = this; const index = e.currentTarget.dataset.index; const sign = e.currentTarget.dataset.type; that.data[sign].splice(index, 1) that.setData({ [sign]: that.data[sign], }) }, /** * 点击 上传图片 按钮 */ btnSave() { //1.0将需要上传的图片模块区分开 let arrs = ['a_img', 'b_img', 'c_img'] let imgArrs = []//将所有的模块图片url地址存放到一个数组中 let imgObjs = {}//用一个对象对图片模块进行标记 for (let i = 0; i < arrs.length; i++) { //上传图片之前当然你要判断当前模块是否有需要上传的图片,现在默认所有模块都有图片需要上传 if (arrs[i].length > 0) { imgArrs.push(...this.data[arrs[i]]) imgObjs[arrs[i]] = this.data[arrs[i]] } } this.setData({ arrImgLength: 1 //设置上传图片从第一张图片开始上传 }) console.log(imgArrs) console.log(imgObjs) this.testUpload(imgArrs, imgObjs) }, /** * 将确定需要上传的图片进行上传 * imgArrs:需要上传的所有图片url地址数组 * imgObjs:将不同图片模块放到一个对象里面 */ testUpload: function (imgArrs, imgObjs) { const that = this api.policy({//如果你开发过小程序,就应该知道这是先前文档定义好的获取oss图片id的后台服务 method: 'POST', data: { fc: 1 }, success: function (res) { if (res.data.code === 0) { let uploadData = res.data.data; wx.uploadFile({ url: uploadData.auth.host, //仅为示例,非真实的接口地址 filePath: imgArrs[that.data.arrImgLength - 1] + '',//要上传的资源路径,也就是我们需要上传的图片url地址 name: "file", formData: { key: uploadData.files[0] + "." + imgArrs[that.data.arrImgLength - 1].split(".")[imgArrs[that.data.arrImgLength - 1].split(".").length - 1], policy: uploadData.auth.policy, signature: uploadData.auth.signature, OSSAccessKeyId: uploadData.auth.accessid, success_action_status: "200", callback: uploadData.auth.callback, }, success: function (res) { let idData = res.data ? JSON.parse(res.data) : {} if (idData.Status == "Ok") {//表示图片上传成功了 //将先前存储的对象进行for in遍历 for (let key in imgObjs) { //将对象里面的数组进行遍历 for (let i = 0; i < imgObjs[key].length; i++) { //判断当前上传的图片url地址和对象存储的url地址是否一致 if (imgObjs[key][i] == imgArrs[that.data.arrImgLength - 1]) { //如果url地址相同说明一致,这样我们就能找到这个图片属于哪个模块的了 that.data[key + 'Id'].push(idData.id)//因为返回来的是代表图片的id,所以也需要将id存储起来 } } } console.log('成功上传第:' + that.data.arrImgLength + '张') ++that.data.arrImgLength//然后将图片上传的张数自加1 //判断当前上传的图片数是否大于存放所有图片url地址的数组长度 if (imgArrs.length < that.data.arrImgLength) { //如果大于说明已经没有图片需要上传了 console.log('所有图片上传完毕') } else { console.log('开始上传第' + that.data.arrImgLength + '张') //如果不大于,说明还需要继续上传图片,然后进行回调 that.testUpload(imgArrs, imgObjs) } } }, fail: function (res) { wx.showModal({ showCancel: false, title: '图片上传失败', }) }, }) } }, fail: function (res) { } }) },
ps:上面的方法解决了一个页面多个图片模块多张图片一次性全部上传的情况,相当于解决了前面的问题1.0;下面解决问题2.0