该示例基于uniapp
先上效果图
实现
// data
data (){
return {
transitionObj: { l: 0, t: 0 }, // 当前摇杆定位
initXY: null, // 原始摇杆xy存储对象
timer: null,
}
}
// dom
<view class="rocker">
<view class="front" @touchstart="onRockerStart" @touchend="onRockerEnd" @touchmove="onRockerMove" @touchcancel="onRockerEnd" :style="{ left: transitionObj.l + 'rpx', top: transitionObj.t + 'rpx' }" />
</view>
// scss
.rocker {
position: absolute;
z-index: 20;
width: 120rpx;
height: 120rpx;
background: rgba(255, 255, 255, 0.2);
border-radius: 50%;
bottom: 35vh;
left: 12vw;
.front {
position: absolute;
z-index: 21;
width: 60rpx;
height: 60rpx;
background: rgba(255, 255, 255, 0.25);
border-radius: 50%;
margin-top: 30rpx;
margin-left: 30rpx;
top: 0;
left: 0;
// transform: translate(-50%, -50%);
transition: none 0s ease 0s;
}
}
onRockerStart
onRockerStart(){
if (!this.initXY) {
const query = uni.createSelectorQuery().in(this);
query
.select(".front")
.boundingClientRect((data) => {
// 记录摇杆操作元素中心位置 (+15: 原点宽度60,圆心需偏量加上半径)
this.initXY = {
x: data.left + 15,
y: data.top + 15,
};
})
.exec();
}
}
onRockerMove
onRockerMove: function (e) {
if (this.timer) return;
const target = e.touches[0];
let y = target.pageY - this.initXY.y; // 鼠标移动y轴距离
let x = target.pageX - this.initXY.x; // 鼠标移动x轴距离
const powV = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); // 斜边长度 (勾股)
// 1.超范围限制 60: 大原点的半径,即120rpx/2;
// 2.当鼠标移动范围大于60时,需要等比处理摇杆中心点实际移动距离
// 3.如图1所示,根据xxx数学定理:
// 3.1 小三角侧边(y) : 大三角底边(y) = 实际移动(r) : 斜长(powV)
// 3.2 小三角侧边(x) : 大三角侧边(x) = 实际移动(r) : 斜长(powV)
const r = 60;
if (powV > r) {
y = r / powV * y;
x = r / powV * x;
}
this.transitionObj = { t: y, l: x };
// 节流
this.timer = setTimeout(() => {
clearTimeout(this.timer);
this.timer = null;
}, 50);
},
- 图1
onRockerEnd
// 清除定时器 并 重置元素位置
onRockerEnd: function (e) {
console.log("结束");
this.transitionObj = { l: 0, t: 0 };
clearTimeout(this.timer);
this.timer = null;
},