From 6f7ac7e5c4af6923ef50ced45531a77eb97b92f2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=82=93=E5=B9=B3=E8=89=BA?= <52643018@qq.com>
Date: Tue, 24 Aug 2021 16:10:16 +0800
Subject: [PATCH] =?UTF-8?q?[=E5=AE=8C=E5=96=84]=20=E4=B8=8A=E4=BC=A0?=
=?UTF-8?q?=E5=9B=BE=E7=89=87=E7=BB=84=E4=BB=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
components/lf-uploadImage/lf-uploadImage.vue | 398 +++++++++++++++++--
pages/test/drag.vue | 25 +-
pages/test/test.vue | 6 +-
3 files changed, 402 insertions(+), 27 deletions(-)
diff --git a/components/lf-uploadImage/lf-uploadImage.vue b/components/lf-uploadImage/lf-uploadImage.vue
index 1f88b0b..9769c7a 100644
--- a/components/lf-uploadImage/lf-uploadImage.vue
+++ b/components/lf-uploadImage/lf-uploadImage.vue
@@ -1,20 +1,40 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 滑动此区域滚动页面
+
@@ -40,15 +60,76 @@
drag: {
type: Boolean, // TODO 是否可拖拽排序图片
default: false
+ },
+ padding: {
+ type: Number, // 图片与图片之间的间距,默认5像素,单位px
+ default: 6
+ },
+ width: {
+ type: String, // 每张图片的宽度,支持百分比,像素,bisection表示等分
+ default: 'bisection'
+ },
+ height: {
+ type: String, // 每张图片高度
+ default: '222rpx'
}
},
data(){
return {
- image_list: []
+ touch: false,
+ startX: 0,
+ startY: 0,
+ columns: 3,
+ item: {},
+ tranX: 0,
+ tranConstX: 0,
+ itemWrap: {},
+ tranY: 0,
+ teanConstY: 0,
+ overOnePage: false,
+ windowHeight: 0,
+ originKey: null,
+ list: [],
+ cur: -1,
+ curZ: -1,
+ image_list: [],
+ itemWrapHeight: 0
}
},
- onLoad(){
-
+ computed: {
+ itemStyle(){
+ let that = this;
+ return function(index, item){
+ let style_obj = {
+ height: that.$props.height
+ }
+
+ let width = that.$props.width;
+ if(width == 'bisection'){
+ width = `calc(${100 / that.columns +'%'} - 4px)`
+ }
+ style_obj.width = width;
+
+ let str = 'translate3d(';
+ if(index === that.cur){
+ str += that.tranX +'px';
+ str += ', ';
+ str += that.tranY +'px';
+ }else{
+ str += item.tranX +'px';
+ str += ', ';
+ str += item.tranY +'px';
+ }
+ str += ', 0px)';
+ style_obj.transform = str;
+ return style_obj;
+ }
+ }
+ },
+ mounted(){
+ // 'https://picsum.photos/200',
+ // 'https://picsum.photos/200/300'
+ this.init();
},
methods: {
// 上传凭证图片
@@ -76,14 +157,16 @@
overstep = true;
}
})
+ this.image_list.push(...image_list);
if(overstep){
uni.showModal({
title: '温馨提示',
content: '您上传的图片含有超出10M大小的限制,请优化大小后再上传!',
showCancel: false
})
+ }else{
+ this.init(); // TODO 优化每次上传都会造成重新初始化导致闪烁
}
- this.image_list.push(...image_list);
}
})
},
@@ -99,11 +182,213 @@
},
// 移除图片
removeInage(current){
+ // 移除已上传的图片
this.image_list.splice(current, 1);
+ // 移除定位的元素(重新初始化)
+ let list = this.image_list.map((item, index) => {
+ return {
+ key: index,
+ tranX: 0,
+ tranY: 0,
+ data: item
+ }
+ }) || [];
+ this.list = list;
+ this.getPosition(list, false); // 重新定位
+ // 重新计算大盒子高度
+ let rows = Math.ceil(list.length / this.columns);
+ let itemWrapHeight = rows * this.item.height;
+ itemWrapHeight += rows * this.$props.padding - this.$props.padding;
+ this.itemWrapHeight = itemWrapHeight;
},
// 返回已上传的图片列表
getUploadImage(){
return this.image_list;
+ },
+ // 长按触发移动排序
+ longPress(e) {
+ this.touch = true;
+ this.startX = e.changedTouches[0].pageX
+ this.startY = e.changedTouches[0].pageY
+ let index = e.currentTarget.dataset.index;
+ if(this.columns === 1) { // 单列时候X轴初始不做位移
+ this.tranConstX = 0;
+ } else { // 多列的时候计算X轴初始位移, 使 item 水平中心移动到点击处
+ this.tranConstX = this.startX - this.item.width / 2 - this.itemWrap.left;
+ }
+ // 计算Y轴初始位移, 使 item 垂直中心移动到点击处
+ this.teanConstY = this.startY - this.item.height / 2 - this.itemWrap.top;
+ this.tranY = this.teanConstY;
+ this.tranX = this.tranConstX;
+ this.cur = index;
+ this.curZ = index;
+ // #ifndef H5
+ uni.vibrateShort();
+ // #endif
+ },
+ // 拖拽中
+ touchMove(e) {
+ if (!this.touch) return;
+ let tranX = e.touches[0].pageX - this.startX + this.tranConstX; // TODO 原作者写的逻辑,但不知道为什么计算不对???
+ let tranY = e.touches[0].pageY - this.startY + this.teanConstY;
+ let overOnePage = this.overOnePage;
+
+ // 判断是否超过一屏幕, 超过则需要判断当前位置动态滚动page的位置
+ if(overOnePage) {
+ if(e.touches[0].clientY > this.windowHeight - this.item.height) {
+ uni.pageScrollTo({
+ scrollTop: e.touches[0].pageY + this.item.height - this.windowHeight,
+ duration: 300
+ });
+ } else if(e.touches[0].clientY < this.item.height) {
+ uni.pageScrollTo({
+ scrollTop: e.touches[0].pageY - this.item.height,
+ duration: 300
+ });
+ }
+ }
+
+ this.tranX = tranX;
+ this.tranY = tranY;
+ let originKey = e.currentTarget.dataset.key;
+ let endKey = this.calculateMoving(tranX, tranY);
+
+ // 防止拖拽过程中发生乱序问题
+ if (originKey == endKey || this.originKey == originKey) return;
+ this.originKey = originKey;
+ this.insert(originKey, endKey);
+ },
+ // 根据当前的手指偏移量计算目标key
+ calculateMoving(tranX, tranY) {
+ let rows = Math.ceil(this.list.length / this.columns) - 1;
+ let i = Math.round(tranX / this.item.width);
+ let j = Math.round(tranY / this.item.height);
+
+ i = i > (this.columns - 1) ? (this.columns - 1) : i;
+ i = i < 0 ? 0 : i;
+
+ j = j < 0 ? 0 : j;
+ j = j > rows ? rows : j;
+
+ let endKey = i + this.columns * j;
+ endKey = endKey >= this.list.length ? this.list.length - 1 : endKey;
+ return endKey
+ },
+ // 根据起始key和目标key去重新计算每一项的新的key
+ insert(origin, end) {
+ let list;
+ if (origin < end) {
+ list = this.list.map((item) => {
+ if (item.key > origin && item.key <= end) {
+ item.key = item.key - 1;
+ } else if (item.key == origin) {
+ item.key = end;
+ }
+ return item
+ });
+ this.getPosition(list);
+ } else if (origin > end) {
+ list = this.list.map((item) => {
+ if (item.key >= end && item.key < origin) {
+ item.key = item.key + 1;
+ } else if (item.key == origin) {
+ item.key = end;
+ }
+ return item
+ });
+ this.getPosition(list);
+ }
+ },
+ // 根据排序后 list 数据进行位移计算
+ getPosition(data, vibrate = true) {
+ let list = data.map((item, index) => {
+ // X轴距离
+ let tranX = this.item.width * (item.key % this.columns);
+ let rows = Math.ceil((item.key+1) / this.columns);
+ let numX = item.key;
+ for(let i=0; i 1){
+ let numY = (rows - 1) * this.$props.padding;
+ tranY = tranY + numY;
+ }
+ item.tranY = tranY;
+ return item
+ });
+
+ this.list = list;
+ if(!vibrate) return;
+ this.itemTransition = true;
+ // #ifndef H5
+ uni.vibrateShort();
+ // #endif
+
+ let image_list = [];
+ list.forEach((item) => {
+ image_list[item.key] = item.data
+ });
+
+ // 元素位置发生改变了,触发change事件告诉父元素更新
+ this.$emit('change', {image_list: image_list});
+ },
+ // 拖拽结束
+ touchEnd() {
+ if (!this.touch) return;
+ this.clearData();
+ },
+ // 清除参数
+ clearData() {
+ this.originKey = -1;
+ this.touch = false;
+ this.cur = -1;
+ this.tranX = 0;
+ this.tranY = 0;
+
+ // 延迟清空
+ setTimeout(() => {
+ this.curZ = -1;
+ }, 300)
+ },
+ // 初始化加载
+ init() {
+ // 拦截image_list为空未上传图片的情况
+ if(!this.image_list.length) return;
+ // 遍历数据源增加扩展项, 以用作排序使用
+ let list = this.image_list.map((item, index) => {
+ return {
+ key: index,
+ tranX: 0,
+ tranY: 0,
+ data: item
+ }
+ });
+ this.list = list;
+ this.itemTransition = false;
+ this.windowHeight = uni.getSystemInfoSync().windowHeight;
+
+ setTimeout(() => {
+ // 获取每一项的宽高等属性
+ this.createSelectorQuery().select(".item").boundingClientRect((res) => {
+ let rows = Math.ceil(this.list.length / this.columns);
+ this.item = res;
+ this.getPosition(this.list, false);
+ let itemWrapHeight = rows * res.height; // TODO 有时候会报res.height undefined
+ itemWrapHeight += rows * this.$props.padding - this.$props.padding;
+ this.itemWrapHeight = itemWrapHeight;
+
+ this.createSelectorQuery().select(".item-wrap").boundingClientRect((res) => {
+ this.itemWrap = res;
+ let overOnePage = itemWrapHeight + res.top > this.windowHeight;
+ this.overOnePage = overOnePage;
+ }).exec();
+ }).exec();
+ }, 300)
}
}
}
@@ -113,14 +398,14 @@
.upload-images{
display: flex;
flex-wrap: wrap;
- margin-top: 30rpx;
- margin-bottom: 18rpx;
.upload-image-item{
- width: 220rpx;
- height: 220rpx;
+ // width: 220rpx;
+ // height: 220rpx;
background: #DDDDDD;
position: relative;
- margin-right: 12rpx;
+ // margin-right: 12rpx;
+ width: 100%;
+ height: 100%;
&:nth-child(3n){
margin-right: 0rpx;
}
@@ -151,4 +436,71 @@
color: #999999;
}
}
+
+ .item-wrap {
+ position: relative;
+ width: 100%;
+ .item {
+ position: absolute;
+ width: 100%;
+ z-index: 1;
+ &.itemTransition {
+ transition: transform 0.3s;
+ }
+ &.zIndex {
+ z-index: 2;
+ }
+ &.cur {
+ background: #1998FE;
+ transition: initial;
+ }
+ }
+ }
+
+ .info {
+ position: relative;
+ // padding-top: 100%;
+ background: #ffffff;
+ // margin-right: 5px;
+ width: auto;
+ height: 100%;
+ &:nth-child(3n){
+ margin-right: 0px;
+ }
+ & > view {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+ box-sizing: border-box;
+ image {
+ width: 100%;
+ height: 100%;
+ }
+ }
+ }
+
+ .indicator {
+ position: fixed;
+ z-index: 99999;
+ right: 0rpx;
+ top: 50%;
+ margin-top: -250rpx;
+ padding: 20rpx;
+ & > view {
+ width: 36rpx;
+ height: 500rpx;
+ background: #ffffff;
+ border-radius: 30rpx;
+ box-shadow: 0 0 10rpx -4rpx rgba(0, 0, 0, 0.5);
+ color: pink;
+ padding-top: 90rpx;
+ box-sizing: border-box;
+ font-size: 24rpx;
+ text-align: center;
+ opacity: 0.8;
+ }
+ }
diff --git a/pages/test/drag.vue b/pages/test/drag.vue
index 91d63e1..8182a66 100644
--- a/pages/test/drag.vue
+++ b/pages/test/drag.vue
@@ -1,6 +1,6 @@
-
+
-
+
@@ -27,7 +27,9 @@
-->
-
+
+
+