效果展示
体验效果
实现步骤
HTML部分
<movable-area class="movableArea">
<movable-view class="sidebar"
:style="borderRadiusStyle"
:x="x"
:y="y"
direction="all"
:animation="false"
@change="onChange"
@touchstart.prevent="onTouchStart"
@touchend.prevent="onTouchend">
<view class="sidebar-more">
<image :src="moreSvg"/>
</view>
</movable-view>
</movable-area>
js部分
data() {
return {
moreSvg,
isTouch: false,
direction: 'right',
x: 0,
y: 0,
x1: 0,
x2: 0,
y1: 0,
y2: 0,
move: {
x: 0,
y: 0
}
}
},
拖动时设置为全圆,并根据操作栏位置设置圆角
computed: {
borderRadiusStyle() {
if (this.isTouch) {
return 'border-radius: 100rpx;'
}
if (this.direction === 'right') {
return 'border-radius: 100rpx 0 0 100rpx;'
}
if (this.direction === 'left') {
return 'border-radius: 0 100rpx 100rpx 0;'
}
return ''
}
},
确定操作栏初始位置,使用 Storage 存储坐标
mounted() {
//确定初始位置
uni.getSystemInfo({
success: (res) => {
const pxToRpx = 750 / res.windowWidth
this.x1 = 0;
this.x2 = Number(res.windowWidth) - 100 / pxToRpx;
this.y1 = 0;
this.y2 = Number(res.windowHeight) - 40 / pxToRpx;
//获取缓存坐标
const bar = uni.getStorageSync('sidebar')
this.direction = bar && bar.x < this.x2 / 2 ? 'left' : 'right'
this.$nextTick(() => {
this.y = bar ? Number(bar.y) : Number(this.y2 * 0.6);
this.x = bar ? Number(bar.x) : Number(this.x2);
this.move.x = this.x;
this.move.y = this.y;
})
}
})
},
在组件销毁前储存当前位置
beforeDestroy() {
try {
if (this.x < this.x2 / 2) {
this.x = this.x1;
} else {
this.x = this.x2;
}
uni.setStorageSync('sidebar', {x: this.x, y: this.y})
} catch (e) {
}
},
拖动时相关代码
onChange(e) {
if (e.detail.source === "touch") {
this.isTouch = true
this.move.x = e.detail.x;
this.move.y = e.detail.y;
}
},
onTouchStart() {
clearTimeout(this.loop)// 再次清空定时器,防止重复注册定时器(会把点击事件也阻止掉)
this.isTouch = false
this.loop = setTimeout(() => {
this.isTouch = true
}, 600)
},
onTouchend() {
clearTimeout(this.loop) // 清空定时器,防止重复注册定时器
if (!this.isTouch) {
//没到触碰时间,触发点击事件
this.onMoreClick()
return
}
this.showList = false
this.x = this.move.x;
this.y = this.move.y;
setTimeout(() => {
if (this.move.x < this.x2 / 2) {
this.x = this.x1;
this.direction = 'left'
} else {
this.x = this.x2;
this.direction = 'right'
}
this.isTouch = false
}, 100)
}
css部分
.movableArea {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none; //设置area元素不可点击,则事件便会下移至页面下层元素
z-index: 100;
}
.sidebar {
pointer-events: auto; //可以点击
height: 100rpx;
width: max-content;
background: #FFFFFF;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 2rpx 4rpx 12rpx 4rpx rgba(0, 0, 0, 0.04);
&-more {
margin: 0 10rpx;
width: 80rpx;
height: 80rpx;
image {
width: 80rpx;
height: 80rpx;
}
}
}
最后(代码地址)
省略了中间的操作列表,感兴趣的可以去看完整代码,代码在 GitHub。