场景:从相册中选择照片,展示图片列表,删除某张不需要的图片,通过拖拽调整图片的位置顺序。
1.wxml
{{(item.upload_percent
<100)?item.upload_percent:item.errormsg}}%
封面
添加图片
小技巧:长按图片拖动可修改封面图片
完成
2.wxss
.uploadPic {
padding: 35rpx 20rpx 0;
box-sizing: border-box;
}
.uploadPic-ul {
box-sizing: border-box;
width: 100%;
padding-bottom: 244rpx;
}
.uploadPic-ul-wrap {
width: 765rpx;
}
.uploadPic-li {
width: 155rpx;
height: 150rpx;
position: relative;
float: left;
margin-right: 30rpx;
margin-bottom: 30rpx;
}
.uploadPic-li .uploadPic-li-camer {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAjCAYAAADmOUiuAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTM4IDc5LjE1OTgyNCwgMjAxNi8wOS8xNC0wMTowOTowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTcgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjQ5RDBDNzkzOThCNzExRTk4NjhBQTU0NDhGMjc1REE4IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjQ5RDBDNzk0OThCNzExRTk4NjhBQTU0NDhGMjc1REE4Ij4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NDlEMEM3OTE5OEI3MTFFOTg2OEFBNTQ0OEYyNzVEQTgiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NDlEMEM3OTI5OEI3MTFFOTg2OEFBNTQ0OEYyNzVEQTgiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4iYtH1AAAC2ElEQVR42syYW4hNURjH1z7GDEWSQYZxbyiTpJMMNeTy4IEUJ+bBG8WQZnJ7oSnmCQ8SUcotwjkuqSFmPEwemMaD0FCjITUPhppcShpm+H/1P1rt9j5n1tp7mfOvX2ufs9dZ63/2Xuv7vr29dDqtLJQAR8A6MAH0gz++Ph77fQdPQSPo9A+USqVyTlRkYa4cNIO5g+w/EcwGm0ENuGV6JUx1w8CcruHgps2tMtEcUKWi6bBLg1dUdB0y6exfg5PAUjDSt+hlE0wGSRWPzoJWmT+Tyeibqg+8x8Zp//eltovl0u8HJWro9QDshNF3WYN3wHpVWJLwNFPWYHUBmhONBhfFYF1Ihx7wcYhNrpBNMj3gxGOwmhtFAuvaPAPJH3kB3oJfDObJkLGV6S7u930nplZxItEW8CXk9y3gIGgPOS8GD4Dtlv5+i8GBgBxaATr4eUbIj2XiozweAzaAqYytveAheAN2gCZwnnnb+AoGSXLtVpo9EXB+I299sRaevIB+EuQawD2wCDwD4+MwWAbuh5yrp7mx4DmYlmP8FJH1/AgsA69dprouXlFJ/E/ymPOv1SRv+XGXBmvZNlhUNOfY7gM/XBj8xLWpLHflArCYx20uDHaxXQnGWYaN3WxbXRjsYbskQtytYNvhwmAf21ERDCZ8Y8VqsJRtZwSDvWynuDBYrgVfW11jW+3C4CxmgW8MuqaS0HLZpUHpe4bHeywM7mUBsoaPD04CtRQE88BLHg9Wp7U/l7bZVSZqZh6+zUr8Q46+A8wcu/j5umkUsHmzUMaCVt4U3CViYiHLLalwuhnrTmlV+SWwKa5yK58qwSsWs1fBsRx9JbBf0IK0scFiS5MeH+QbWa20sFr5ySJ3OV8uVUYIS8OKOGAUSVm/jcStREILnoWobjF4EnwtUIP12TBTZVqK/wfJq4+m7C6WxT2fT2CS0kYEPO25lsc5P8urGJiTZKD+CjAABiiPPK6k5x4AAAAASUVORK5CYII=);
background-repeat: no-repeat;
background-position: center 37rpx;
background-size: 40rpx 35rpx;
width: 100%;
height: 100%;
position: absolute;
background-color: #f2f2f2;
top: 0;
left: 0;
box-sizing: border-box;
padding-top: 86rpx;
text-align: center;
font-size: 24rpx;
color: #aaa;
line-height: 28rpx;
}
.uploadPic-li-pic {
width: 155rpx;
height: 150rpx;
position: absolute;
left: 0;
top: 0;
}
movable-view, movable-view .item-move, movable-view .item-move image {
width: 155rpx;
height: 150rpx;
}
.uploadPic-li-fm {
width: 100%;
height: 35rpx;
line-height: 35rpx;
text-align: center;
background-color: #ff7500;
font-size: 24rpx;
color: #fff;
position: absolute;
left: 0;
bottom: 0;
}
.uploadPic-li-close {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAAXCAYAAADgKtSgAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTM4IDc5LjE1OTgyNCwgMjAxNi8wOS8xNC0wMTowOTowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTcgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkM0MDlCQ0MzOThCODExRTlCRTdCODYyQzA0QjY4MEJFIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkM0MDlCQ0M0OThCODExRTlCRTdCODYyQzA0QjY4MEJFIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6QzQwOUJDQzE5OEI4MTFFOUJFN0I4NjJDMDRCNjgwQkUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6QzQwOUJDQzI5OEI4MTFFOUJFN0I4NjJDMDRCNjgwQkUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7vcILQAAAA9klEQVR42rSVSw6CMBBACzGsvY6uYSUu9HCi4hWMS7yB7nAh3RpPoD1BnUlmCCE0gHSaPGhpeW36mSqrlHIQAjGwA0rgA1h6l/Q9pnadDpc4BSqS9VFR+155BOwHStsc6P9OOVYUf4qZotlBU36cKGbytnzlScykLMfVfnqWa/Qq2k5WgCSEwW+VTNqgfCkkXwR44iAzF5AblNu6aO10ZRDUWZyWr9C0mBk83vW0NHr1kF448pvQyO8oPwvJL3xCtdQJ5fjtU75uR8Xck/gkFc+vrnjOHeQTRhwNvUP1iMVLx1zQvIsSIAMegCGZoXJG9c7b/yfAALbzUJhUQ+vrAAAAAElFTkSuQmCC);
background-repeat: no-repeat;
background-position: center;
background-size: 23rpx 23rpx;
width: 23rpx;
height: 23rpx;
padding: 10rpx;
position: absolute;
right: -22rpx;
top: -22rpx;
}
.uploadPicB {
width: 678rpx;
position: fixed;
bottom: 0;
left: 50%;
margin-left: -339rpx;
padding-bottom: 90rpx;
}
.uploadPicB-msg {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAbCAYAAACTHcTmAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTM4IDc5LjE1OTgyNCwgMjAxNi8wOS8xNC0wMTowOTowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTcgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjc5ODFERjJCOThCQzExRTlCNUFFOTUxQTkzNDQ5RDYyIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjc5ODFERjJDOThCQzExRTlCNUFFOTUxQTkzNDQ5RDYyIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6Nzk4MURGMjk5OEJDMTFFOUI1QUU5NTFBOTM0NDlENjIiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6Nzk4MURGMkE5OEJDMTFFOUI1QUU5NTFBOTM0NDlENjIiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7B1bc1AAACCUlEQVR42qSVSygFURjHZ9wrJEqU93tBIeWRUgixYYGysPMo5NHdcDc2FqSuDQvK5nplYYssJIkoZCdRqBulEKK8boz/xzd1umaYMV/9zumeM/O75zuvkZVeSS9yQTMoAllC+wnYAlNgXXIpP16UNaQpYBjUCW1n4AYEgwyhfRP0QLwrCvx8hDXglIVroBpEglRQADJBKCgH85zFjuSUO/VGWsoiiiZO76+oBAsgALRgxG5RSv9+C2ygmNMyGvGcnT9Ih/hYTX+chR0mhRIk5yhL+NecOtII1NfgEsRIZkNdfae8grIC5NFIG7h7SLIW/ep6+PGqSsIi/Tf2uM4naTT/eLCkdClelPcgkaSv3GyTrAftgDeSerghypLOKYfwiTsi6bKw4a1ELderJF3kKWi1KB3k2q1ufgfXS/9MvQ9lHBjDgt2o0gmwDapoHU0KG1EOADpZ3b63VBnflXQbOA0q6Z1J8AwKMUpF6z4NBHdcywak+yAHJEHo0btPX8CVieTTeON7xEa7xoMHIAGMCEfPNxS+vGlfXvh2aknbWOYwMFKS1xuRXvDng+YqHHxoPEPT9viVlUu5MiKleALJIFanX+YLaEOrU0+aDWYMpE/vjxqVHoIuEMYjsvH8yTwddt5202ZG6v06ct9Hj45gEHjnuaS+2d++ZfY/0qNj167Rns5fXc34FGAAZQl6B31aWcAAAAAASUVORK5CYII=);
background-repeat: no-repeat;
background-position: left center;
background-size: 21rpx 27rpx;
padding-left: 33rpx;
color: #666;
font-size: 28rpx;
line-height: 32rpx;
}
.uploadPicB-btn {
width: 100%;
height: 90rpx;
line-height: 90rpx;
text-align: center;
color: #fff;
font-size: 30rpx;
border-radius: 10rpx;
margin-top: 35rpx;
background-color: #ff7500;
}
.uploadPic-li-msg {
width: 100%;
height: 100%;
position: absolute;
background-color: #f2f2f2;
top: 0;
left: 0;
box-sizing: border-box;
padding-top: 55rpx;
text-align: center;
font-size: 24rpx;
color: #aaa;
line-height: 28rpx;
word-break: break-all;
word-wrap: break-word;
z-index: 1;
}
movable-area {
width: 100%;
height: 100%;
}
3.js
var app = getApp();
// 这里是请求方法的封装
// var common = require('../../util/util.js');
var that;
Page({
/**
* 页面的初始数据
*/
data: {
tempFilePaths: [],
// 最大照片数量的限制
imgnum: 6,
disabled: true,
elements: [],
hidden: true,
flag: false,
x: 0,
y: 0,
uploadPicKind: ''
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function(options) {
that = this;
},
// 照片张数计算(和计算每张图片的位置,如果需要计算位置nodes=false,否则为true)
getNumPic() {
var num = that.data.tempFilePaths.length;
var title = '上传照片(' + num + ')张';
wx.setNavigationBarTitle({
title: title
});
},
// 获取图片的信息(位置信息)
getElements(){
var query = wx.createSelectorQuery();
var nodesRef = query.selectAll(".uploadPic-li-pic");
nodesRef.fields({
dataset: true,
rect: true
}, (result) => {
for (var i = 0; i < result.length; i++) {
result[i].dataset['index'] = i
}
that.setData({
elements: result
});
}).exec();
},
/*****
* 上传图片
********/
uploadpic: function(e) {
var tempFilePaths = that.data.tempFilePaths;
let num = that.data.imgnum - that.data.tempFilePaths.length;
wx.chooseImage({
count: num, // 默认9
sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
success: function(res) {
// 返回选定照片的本地文件路径列表,tempFilePath可以作为img标签的src属性显示图片
var path = res.tempFiles;
for (var i in res.tempFiles) {
/**** 这里如果换为了服务器的,这里的 upload_percent 就得写为0,土武器上传完毕会改为对应的进度****/
path[i]['upload_percent'] = 100;
path[i]['src'] = '';
path[i]['iserror'] = 0;
path[i]['errormsg'] = '';
tempFilePaths.push(path[i]);
}
that.setData({
tempFilePaths: tempFilePaths
}, () => {
// 等赋值完毕后,再统计照片张数
that.getNumPic();
// 图片位置信息
that.getElements();
});
// 上传服务器 (图片不能一次上传多张,需要一张一张上传,用了一个循环)
for (var j in tempFilePaths) {
if (tempFilePaths[j]['upload_percent'] == 0) {
// that.upload_file_server(j)
}
}
}
})
},
// 上传服务器
upload_file_server: function(j) {
var keyinfo = that.data.tempFilePaths[j];
var key = "tempFilePaths[" + j + "]";
var upload_task = wx.uploadFile({
// 这里是图片上传的图片服务器地址
url: common.config.Sever_uploadImg,
filePath: keyinfo['path'],
name: 'file',
success: function(res) {
var returndata;
if (typeof res.data == 'string') {
returndata = JSON.parse(res.data)
}
if (res.statusCode != 200) {
keyinfo['iserror'] = 1;
keyinfo['errormsg'] = '网络错误';
} else {
if (returndata.code) {
keyinfo['src'] = returndata.data;
keyinfo['iserror'] = 0;
keyinfo['errormsg'] = '成功';
} else {
keyinfo['iserror'] = 1;
keyinfo['errormsg'] = returndata.msg;
}
}
// 只是改变其中的某项
that.setData({
[key]: keyinfo,
});
}
});
upload_task.onProgressUpdate((res) => {
keyinfo['upload_percent'] = res.progress
that.setData({
[key]: keyinfo,
});
})
},
/*****
* 删除图片
********/
delimg: function(e) {
var datalist = that.data.tempFilePaths;
var thiskey = e.currentTarget.dataset.keyindex;
datalist.splice(thiskey, 1);
that.setData({
tempFilePaths: datalist
}, () => {
// 照片张数统计
that.getNumPic();
});
},
// 完成按钮
uploadPicFinshed() {
// 点击完成后的动作
var tempFilePaths = that.data.tempFilePaths;
},
// 拖拽逻辑
//长按
_longtap: function(e) {
var maskImg = e.currentTarget.dataset.img
this.setData({
maskImg: maskImg
});
this.setData({
x: e.currentTarget.offsetLeft,
y: e.currentTarget.offsetTop
})
this.setData({
hidden: false,
flag: true
})
},
//触摸开始
touchs: function(e) {
this.setData({
beginIndex: e.currentTarget.dataset.index
})
},
//触摸结束
touchend: function(e) {
if (!this.data.flag) {
return;
}
const x = e.changedTouches[0].pageX
const y = e.changedTouches[0].pageY
const list = this.data.elements;
let data = this.data.tempFilePaths
for (var j = 0; j < list.length; j++) {
const item = list[j];
if (x > item.left && x < item.right && y > item.top && y < item.bottom) {
const endIndex = item.dataset.index;
const beginIndex = this.data.beginIndex;
//向后移动
if (beginIndex < endIndex) {
let tem = data[beginIndex];
for (let i = beginIndex; i < endIndex; i++) {
data[i] = data[i + 1]
}
data[endIndex] = tem;
}
//向前移动
if (beginIndex > endIndex) {
let tem = data[beginIndex];
for (let i = beginIndex; i > endIndex; i--) {
data[i] = data[i - 1]
}
data[endIndex] = tem;
}
this.setData({
tempFilePaths: data
});
}
}
this.setData({
hidden: true,
flag: false
})
},
//滑动
touchm: function(e) {
if (this.data.flag) {
const x = e.touches[0].pageX
const y = e.touches[0].pageY
this.setData({
x: x - 77,
y: y - 75
})
}
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function() {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function() {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function() {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function() {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function() {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function() {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function() {
}
})
4.效果
5.说明
5.1拖拽参照:
https://blog.csdn.net/haicome/article/details/82664344
https://blog.csdn.net/qq_35736512/article/details/89153197
5.2 小程序中的拖拽比较简单,小程序官方提供了组件
点击这里查看https://developers.weixin.qq.com/miniprogram/dev/component/movable-area.html
5.3 从相册选择照片或者相机拍照 wx.chooseImage
点击查看https://developers.weixin.qq.com/miniprogram/dev/api/media/image/wx.chooseImage.html
5.4 wx.uploadFile 官方地址
点击查看 https://developers.weixin.qq.com/miniprogram/dev/api/network/upload/wx.uploadFile.html
5.5 wx.createSelectorQuery 官方地址
点击查看 https://developers.weixin.qq.com/miniprogram/dev/api/wxml/wx.createSelectorQuery.html
5.6 图片裁剪
点击查看https://github.com/wx-plugin/image-cropper