—使用前必看—
本篇文章主要内容是实现在两个相同大小(宽高)下进行位置拖动摆放,以及对其他物体摆放位置造成偏移位置的功能效果,但是目前还只能在两个宽高一样的物体进行拖动。
本人耗时一天写出来的拖动摆放功能,目前bug还是有比较多需要完善的。大家可以作为一个思路参考。
—效果—
—代码—
<template>
<view :style="{height:heightV + 'rpx'}">
<view style="padding: 10rpx;position: absolute;"
:style="{top: mY+'rpx',left: mX + 'rpx'}" v-show="hide">
<view style="background-color: rgba(0,0,0, 0.2);"
:style="{width:(hideW-10) + 'rpx',height: (hideH-10) + 'rpx'}">
</view>
</view>
<view v-for="(item,index) in data" :key="index"
style="
padding: 10rpx;
position: absolute;"
:style="{
top:regions[item.regionID].y + 'rpx',
left:regions[item.regionID].x+'rpx',
width:(regions[item.regionID].wME-10) + 'rpx',
height:(regions[item.regionID].hME-10) + 'rpx',
}"
@touchmove="move($event,item)"
@touchstart="moveF(item)"
@touchend="moveE(item.regionID)">
<view style="background-color: white;width: 100%;height: 100%">
<text>{{item.text}}</text>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
data:[
{
text:'测试1',
regionID: 0,
wME: 100,
hME: 100
},
{
text:'测试2',
regionID: 1,
wME: 100,
hME: 100
}
],
regions:[
{
y:0,
x:0,
wME: 100,
hME: 100
},
{
y:100,
x:100,
wME: 100,
hME: 100
}
],
mY:0,
mX:0,
widthV:'',
heightV:'',
hide: false,
hideW:0,
hideH:0
}
},
onLoad() {
// 获取初始宽高
this.widthV = uni.getSystemInfoSync().windowWidth*2
this.heightV = uni.getSystemInfoSync().windowHeight*2
},
methods: {
move(e,item){
// 判断当前移动到的区域是否有物品
this.isGoods(item.regionID)
// 获取当前物体宽高
let w = item.wME
let h = item.hME
// 获取当前位置(左上角的点)
let newY = e.changedTouches[0].pageY*2 - h/2
let newX = e.changedTouches[0].pageX*2 - w/2
item.x = newX
item.y = newY
// 更新当前固定坐标的位置
this.mY = Math.round(newY/h) * h
this.mX = Math.round(newX/w) * w
this.regions[item.regionID] = item
// 更新当前布局样式(产生拖动效果)
this.$forceUpdate()
},
moveF(item){
// 第一次点击物品时生成固定坐标位置
this.mY = this.regions[item.regionID].y
this.mX = this.regions[item.regionID].x
this.hide = true
this.hideW = item.wME
this.hideH = item.hME
},
moveE(id){
this.hide = false
// 固定当前位置
let item = this.regions[id]
// 获取当前物体宽高
let w = item.wME
let h = item.hME
item.y = Math.round(item.y/h) * h
item.x = Math.round(item.x/w) * w
// 判断当前是否超出边界
if(item.x < 0) item.x =0;
if(item.x+w > this.widthV) item.x =Math.floor((this.widthV-w)/w)*w;
if(item.y < 0) item.y =0;
// 修改位置信息
this.regions[id] = item
// 更新
this.$forceUpdate()
},
isGoods(id){
// 获取当前位置信息
let nowY = this.regions[id].y
let nowX = this.regions[id].x
let item = {}
// 获取到当前移动物体的宽高
let w = this.regions[id].wME
let h = this.regions[id].hME
// 定义条件宽高范围
let hY = h-h/4
let hX = w-w/4
// 遍历除自身意外物品的位置,实现一个物品独占一个空间
for (var i = 0; i < this.regions.length; i++) {
// 得到当前物体坐标信息
item = this.regions[i]
// 判断除了自己以外的
if(i != id){
// 当前物体上下位置发生的变化
if(item.y <= nowY + hY && item.y + hY >= nowY){
// 判断当前物体是否在发生位置物品的下方
if(item.x >= nowX - 25 && item.x <= nowX + 25){
if(this.mY - nowY < 0){
item.y += h
if(item.y + h > this.heightV){
this.heightV += h
}
}else {
// 判断当前是否到顶部
if(item.y == 0){
if(item.x - w > 0){
item.x -= w
}else {
item.x += w
}
}else {
item.y -= h
}
}
// 下面三行属于边界判定,当处于边界时发生的动作
if(item.x < 0) item.x =0;
if(item.x+w > this.widthV) item.x =Math.floor((this.widthV-w)/w)*w;
if(item.y < 0) item.y =0;
this.regions[i] = item
}
}
// 当前物体左右位置发生的变化
if(item.x <= nowX + hX && item.x + hX >= nowX){
if(item.y >= nowY - 25 && item.y <= nowY + 25){
// 判断当前移动的物体左右拖动
if(this.mX - nowX < 0){
item.x += w
}else {
if(item.x==0){
if(item.y - h > 0){
item.y -= h
}else {
item.y += h
}
}else {
item.x -= w
}
}
// 下面三行属于边界判定,当处于边界时发生的动作
if(item.x < 0) item.x =0;
if(item.x+w > this.widthV) item.x =Math.floor((this.widthV-w)/w)*w;
if(item.y < 0) item.y =0;
this.regions[i] = item
}
}
// 当物体斜向移动发生的变化
if ((item.y <= nowY + hY && item.y + hY >= nowY) && (item.x <= nowX + hX && item.x + hX >= nowX)){
// 判断当前移动的物体左右拖动
if(this.mX - nowX < 0){
item.x += w
}else {
if(item.x==0){
if(item.y - h > 0){
item.y -= h
}else {
item.y += h
}
}else {
item.x -= w
}
}
// 下面三行属于边界判定,当处于边界时发生的动作
if(item.x < 0) item.x =0;
if(item.x+w > this.widthV) item.x =Math.floor((this.widthV-w)/w)*w;
if(item.y < 0) item.y =0;
this.regions[i] = item
}
}
}
}
}
}
</script>
<style>
</style>
—逻辑代码思路—
- 拖动:通过使用判断当前点击屏幕时相对左上角的点去进行x y轴的定位。通过公式:*坐标值(默认单位px)2 - 当前物体宽或高(默认单位rpx)/2。一般 px 是 rpx 的两倍,通过这个得出上面的公式。
- 阴影固定:通过每一次拖动时发生位移,设置位移到一个固定范围内将位置移到一个固定位置,也就是说当前松开拖动的物体时物体坐标将锁定在阴影的位置上。实现一个锁定功能可以方便看到当前拖动的物体已拖动到哪个位置上。
- 物体拖动碰撞:通过提前把每个物体的坐标位置放在数组中,当一个物体发生位移时除去自身的位置去判断当前移动到的下一个位置是否有物体存在。通过这个方法判断出当下一个移动位置有物体时将碰撞到的物体使它发生位移。
—目前问题—
- 目前逻辑代码在拖动物体碰撞使碰撞物体发生位移时,只能在两个相同大小(宽高)下去进行完成。
- 当拖动物体发生碰撞时在向下移动的时候,虽然可以将当前高度增加。但它无法还原(意思就是最下面没有物体的时候不会恢复原来的样子)。
- 代码相对来说比较繁杂没有进行封装成方法处理,代码上的逻辑比较复杂不容易看懂。
—思路演变—
本人一开始在想如何实现这种效果的时候,首先想到的是通过css的浮动去实现,通过改变当前的位置来达到物体上的拖动,在两个物体上的碰撞先是通过上面位置拖动去改变,但是发现还有有问题,以为值都是直接赋在物体的宽高上面。后面才发现通过把所有物体的坐标放在一个数组里面,通过拖动某一个物体的时去判断当前拖动位置上是否有物体存在。类似于将这个拖动物体与所有物体的坐标加上宽高的这么一个范围去判断是否有在这个区域内。
—源码位置—
后面有更新的话会在这个里面更新~
如果有想和我一起把这个功能完善的小伙伴也可以私信找我哦~