Files
im-system/im-uniapp/components/zmm-upload-image/zmm-upload-image-drag.vue
2023-12-01 23:57:44 +08:00

320 lines
8.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view @touchmove.stop.prevent="moveHandle" class="moveWrap">
<movable-area class="movarea" ref="areaBox" id="areaBox" :style="{height:imgSize*rowNum +200+ 'rpx'}">
<view class="imgBox" :style="{height:imgSize*rowNum + 'rpx'}">
<view :id="'img' + idx" class="imgItem" v-for="(item, idx) in imgList" :key="idx"
:style="{transition:addJump?' all 0.5s':'',opacity:idx===selectIdx?'0':'1', width: imgSize + 'rpx', height: imgSize + 'rpx', borderRadius:imgRadius+'rpx',padding:imgPadding+'rpx',left:(hoverImgIdx==='img'+idx?curHoverBoxMove.x+'rpx':''),top:(hoverImgIdx==='img'+idx?curHoverBoxMove.y+'rpx':'')}">
<view class="imgItem-img" @tap="itemclick(item,idx)" @touchstart="tstr(idx, $event)" @touchmove="tsmo" @touchend="toend">
<image v-if="item.videoUrl" class="imgItem-play" src="../../static/img/bf.png" mode="aspectFill"></image>
<image :style="{borderRadius:imgRadius+'rpx' }" :ref="'img' + idx" :src="item.url" mode="aspectFill"></image>
</view>
</view>
<slot></slot>
</view>
<movable-view v-if="moveSrc" :animation="false" class="moveV" :x="x" :y="y" direction="all"
@change="onChange"
:style="{ width: imgSize + 'rpx', height: imgSize + 'rpx',padding:imgPadding+'rpx' }">
<image v-if="moveSrc.videoUrl" class="imgItem-play" src="../../static/img/bf.png" mode="aspectFill"></image>
<image :style="{borderRadius:imgRadius+'rpx' }" :src="moveSrc.url" mode="aspectFill"></image>
</movable-view>
</movable-area>
<view v-if="showDelete">
<view class="delete" :class="{'deleteType':deleteType}">
<text v-if="deleteType">松开删除</text>
<text v-else>拖动到此处删除</text>
</view>
</view>
</view>
</template>
<script>
export default {
emits:['itemclick','update:imgList','deleteImage','change','moveEndList'],
props: {
//图片列表
imgList: {
type: Array,
default: function() {
return [];
}
},
//图片大小
imgSize: {
type: Number
},
//图片间距
imgPadding: {
type: Number
},
//图片行数
rowNum: {
type: Number
},
//图片圆角
imgRadius: {
type: Number
}
},
components: {},
data() {
return {
showDelete:false,
touchobj:null,
deleteType:false,
addJump:false,
areaBoxInfo: {},
x: 0,
y: 0,
selectIdx: null,
moveSrc: null,
areaBoxTop: 0,
hoverImgIdx: '',
inBoxXY: {},
curHoverBoxMove: {
x: 0,
y: 0
}
};
},
watch: {
hoverImgIdx(e) {
let idx = this.selectIdx
let hoverIdx = parseInt(e.split('img')[1]);
if (this.imgList[idx]) {
let selectRow = this.imgList[idx].y / uni.upx2px(this.imgSize)
let selectColum= this.imgList[idx].x / uni.upx2px(this.imgSize)
let hoverRow = this.imgList[hoverIdx].y / uni.upx2px(this.imgSize)
let hoverColum= this.imgList[hoverIdx].x / uni.upx2px(this.imgSize)
let left = -(this.imgSize * (hoverColum - selectColum))
let top= -(this.imgSize * (hoverRow - selectRow))
this.curHoverBoxMove = {
x: left,
y: top,
}
}
},
// imgList(e){
// console.log('变化了item')
// this.$nextTick(()=>{
// this.setImgXy()
// })
// }
imgList: {
deep: true,//深度监听可见听对象中的元素变化例:obj.id
immediate:false,//在进入页面时第一次绑定值不会立刻执行监听只有数据发生改变才会执行handler中的操作
handler(val) {//watch事件
// console.log('变化了item')
this.$nextTick(()=>{
this.setImgXy()
})
}
}
},
methods: {
itemclick(e,i){
this.$emit('itemclick',e,i)
},
moveHandle() {
return;
},
deleteImage: function(e) {
var index = e
var deletedImage = this.imgList[index]
this.imgList.splice(index, 1)
this.$emit('deleteImage', deletedImage)
},
onChange(e) {
var boxHeight=this.imgSize * this.rowNum
var deleteHeight=(boxHeight-80)/2
if(e.detail.y>deleteHeight){
this.deleteType=true
}else{
this.deleteType=false
}
this.showDelete=true
this.$emit('change',e)
},
tstr(e, s) {
this.touchobj=this.imgList[e]
this.addJump=true
this.getDomInfo('areaBox', info => {
this.areaBoxInfo = info;
//获取拖拽区域的上边距和下边距
let areaBoxTop = this.areaBoxInfo.top;
let areaBoxLeft = this.areaBoxInfo.left;
// 设置可移动方块的初始位置为当前所选中图片的位置坐标
this.x = this.imgList[e].x;
this.y = this.imgList[e].y;
//显示可移动方块
this.moveSrc = this.imgList[e];
//保存当前所选择的图片索引
this.selectIdx = e;
var x = s.changedTouches[0].clientX - areaBoxLeft;
var y = s.changedTouches[0].clientY - areaBoxTop;
// 保存鼠标在图片内的坐标
this.inBoxXY = {
x: x - this.imgList[e].x,
y: y - this.imgList[e].y,
}
});
},
tsmo(e) {
let areaBoxTop = this.areaBoxInfo.top;
let areaBoxLeft = this.areaBoxInfo.left;
let imgSize = this.imgSize;
//重置为以拖拽盒子左上角为坐标原点
var x = e.changedTouches[0].clientX - areaBoxLeft;
var y = e.changedTouches[0].clientY - areaBoxTop;
this.x = x - this.inBoxXY.x;
this.y = y - this.inBoxXY.y;
this.imgList.forEach((item, idx) => {
if (x > item.x && x < item.x + imgSize && y > item.y && y < item.y + imgSize) {
this.hoverImgIdx = 'img' + idx
}
});
},
toend(e) {
this.addJump=false
if(this.deleteType){
this.deleteImage(this.selectIdx)
}else{
// 移动结束隐藏可移动方块
let beforeIdx = this.selectIdx;
let afterIdx = parseInt(this.hoverImgIdx.split('img')[1]);
if (this.hoverImgIdx !== '' && beforeIdx !== afterIdx) {
this.imgList[beforeIdx] = this.imgList[afterIdx];
this.imgList[afterIdx] = this.moveSrc;
this.$emit('moveEndList', this.imgList);
}
}
this.moveSrc = '';
this.hoverImgIdx = ''
this.selectIdx = null
this.deleteType=false
this.showDelete=false
this.$nextTick(()=>{
this.setImgXy()
})
},
getDomInfo(id, callBack) {
const query = uni.createSelectorQuery().in(this);
query.select('#' + id)
.boundingClientRect()
.exec(function(res) {
callBack(res[0]);
});
},
setImgXy(){//设置每个图片的基础xy轴
this.getDomInfo('areaBox', info => {
this.areaBoxInfo = info;
// 设置区域内所有图片的左上角坐标
this.imgList.forEach((item, idx) => {
this.getDomInfo('img' + idx, res => {
item.x = res.left - info.left;
});
this.getDomInfo('img' + idx, res => {
item.y = res.top - info.top;
});
});
});
}
},
mounted() {
this.setImgXy()
}
};
</script>
<style lang="scss" scoped>
.imgItem-play{
z-index: 1;
position: absolute;
left: 50%;
top: 50%;
width: 80rpx !important;
height: 80rpx !important;
transform: translate(-50%,-50%);
}
.movarea {
width: 100%;
height: 320rpx;
display: flex;
flex-direction: row;
}
.imgBox {
position: relative;
z-index: 1;
width: 100%;
height: 320rpx;
display: flex;
flex-direction: row;
flex-wrap: wrap;
.imgItem {
position: relative;
box-sizing: border-box;
left: 0;
top: 0;
box-sizing: border-box;
image {
width: 100%;
height: 100%;
// transition: all 0.2s;
vertical-align: top;
}
}
}
.moveV {
opacity: 0.6;
z-index: 0;
box-sizing: border-box;
image {
width: 100%;
height: 100%;
}
}
.select {
opacity: 0;
}
.zmm-upload-image-deleteIcon {
right: 0rpx;
top: 0rpx;
position: absolute;
background-color: rgba(0, 0, 0, 0.3);
width: 36rpx;
height: 36rpx;
text-align: center;
border-radius: 50%;
color: white;
font-size: 30rpx;
z-index: 2;
display: flex;flex-direction: row;align-items: center;justify-content: center;
}
.delete{
position: absolute;
bottom: 0rpx;
left: 0;
width: 100%;
height: 80rpx;
line-height: 80rpx;
background: #C04A42;
text-align: center;
transition: all 0.3s;
}
.delete text{
color: #fff;
}
.deleteType{
transform: scale(1.1);
}
.moveWrap{
position: relative;
}
.imgItem-img{
width: 100%;
height: 100%;
}
</style>