背景:
智慧养殖移动端表格页有添加功能,但是当列表很长时按钮会遮挡数据,如下图:
所以就需要支持拖动,同时需要一个吸边的效果:
拖拽原理
从一个位置移动到另一个位置,实时更改元素的位置 🤷
移动
<template>
<view id="app">
<view class="move-button" @touchmove="handleTouchMove" :style="[style]"></div>
</view>
</template>
<script>
export default {
name: 'App',
data() {
return {
style: {},
};
},
methods: {
handleTouchMove(e) {
console.log(e);
const { clientX, clientY } = e.touches[0];
this.style = {
left: `${clientX}px`,
top: `${clientY}px`,
};
},
},
};
</script>
<style>
.move-button {
position: absolute;
top: 200px;
right: 0;
width: 200px;
height: 200px;
background-color: blue;
}
</style>
以上代码基本是可以移动元素,但是有个明显的问题,当开始移动的瞬间元素会跳动一下:
原因是:移动时获取的坐标赋值给的是元素的左上角坐标 。
那如何和处理?
我们只要设置的位置不是元素左上角,而是设置元素的拖动点就行。实际是不能设置元素内某个点的位置,我们需要变通下。我们发现拖动元素时,拖动点和元素的左上角的位置之间的差是不变的:
只要在拖动开始时,获得元素左上角的位置(posX,posY)以及拖动点的起始位置(startX,startY)然后 x,y 方向相减:
const diffX = startX - posX,
diffY = startY - posY
获取元素的信息:
getElementInfo(selector){
let view = uni.createSelectorQuery().in(this).select(selector)
return new Promise((resolve, reject)=>{
view.boundingClientRect(data => {
resolve({
top:data.top,
right:data.right,
bottom:data.bottom,
left:data.left,
width:data.width,
height:data.height,
})
}).exec();
})
}
handleTouchStart(e){
this.elemInfo = await this.getElementInfo('.add-img')
const {clientX,clientY} = e.touches[0]
this.diffX = clientX - this.elemInfo.left
this.diffY = clientY - this.elemInfo.top
}
修改 handleTouchMove
:
handleTouchMove(e) {
console.log(e);
const { clientX, clientY } = e.touches[0];
this.moveX = clientX - this.diffX
this.moveY = clientY - this.diffY
this.setButtonPosition()
},
setButtonPosition(){
this.style = {
left:this.moveX + 'px',
top:this.moveY + 'px'
}
}
吸边
原理:当元素的中心点位置小于页面宽度一半时,吸附到左边,反之吸附到右边 。
拖动停止后,根据上述原理设置 x 的坐标:
suctionSide(){
const halfWidth = this.pageWidth/2
const elemCenterPointX = this.moveX + this.elemInfo.width/2
if(elemCenterPointX < halfWidth){
// 按钮中心点位置小于一半,吸附到左边
this.moveX = 0
}else{
// 按钮中心点位置大于一半,吸附到右边
this.moveX = this.pageWidth - this.elemInfo.width
}
this.setButtonPosition()
}
获取页面宽度:
uni.getSystemInfo({
success:res=>{
console.log(res)
this.pageWidth = res.windowWidth
}
})
未完待续…
参考: