1.仿照vant4的FloatingBubble组件实现一个简单的FloatingBubble组件。 可以在指定范围内拖动,目前做的是不超出屏幕范围,做了边界处理。
<template>
<div
class="floating-bubble"
:style="{
top: snappedTop + 'px',
left: snappedLeft + 'px',
}"
@touchstart="handleTouchStart"
@touchmove="handleTouchMove"
@touchend="handleTouchEnd"
>
<slot />
</div>
</template>
<script>
export default {
data() {
return {
windowWidth: 0,
windowHeight: 0,
isDragging: false, // 拖动状态
startX: 0, // 拖动起始点的X坐标
startY: 0, // 拖动起始点的Y坐标
left: 0, // 悬浮气泡的left位置
top: 0, // 悬浮气泡的top位置
}
},
methods: {
handleTouchStart(event) {
this.isDragging = true
this.startX = event.touches[0].clientX - this.left
this.startY = event.touches[0].clientY - this.top
},
handleTouchMove(event) {
if (!this.isDragging) return
event.preventDefault()
const touchX = event.touches[0].clientX
const touchY = event.touches[0].clientY
this.left = touchX - this.startX
this.top = touchY - this.startY
this.handleBoundary() // 处理边界
},
handleTouchEnd() {
this.isDragging = false
},
handleBoundary() {
const threshold = 60 // 边缘阈值
// 处理左边界
if (this.left < threshold) {
this.left = 0
}
// 处理上边界
if (this.top < threshold) {
this.top = 0
}
// 处理右边界
const windowWidth =
window.innerWidth ||
document.documentElement.clientWidth ||
document.body.clientWidth
if (windowWidth - this.left < threshold) {
this.left = windowWidth - 50
}
// 处理下边界
const windowHeight =
window.innerHeight ||
document.documentElement.clientHeight ||
document.body.clientHeight
if (windowHeight - this.top < threshold) {
this.top = windowHeight - 130
}
},
},
computed: {
snappedLeft() {
return this.left
},
snappedTop() {
return this.top
},
snappedRight() {
const windowWidth = this.windowWidth
const elementWidth = 50 // 元素的宽度
const threshold = 20 // 边缘阈值
const maxRight = windowWidth - elementWidth - threshold
if (this.left > maxRight) {
return maxRight
} else if (this.left < threshold) {
return threshold
}
return this.left
},
snappedBottom() {
const windowHeight = this.windowHeight
const elementHeight = 100 // 元素的高度
const threshold = 20 // 边缘阈值
const maxBottom = windowHeight - elementHeight - threshold
if (this.top > maxBottom) {
return maxBottom
} else if (this.top < threshold) {
return threshold
}
return this.top
},
},
mounted() {
//计算初始位置
this.windowWidth =
window.innerWidth ||
document.documentElement.clientWidth ||
document.body.clientWidth
this.windowHeight =
window.innerHeight ||
document.documentElement.clientHeight ||
document.body.clientHeight
this.left = this.windowWidth - 50
this.top = this.windowHeight / 2
},
}
</script>
<style scoped>
.floating-bubble {
position: fixed;
/* border-radius: 50%; */
width: fit-content;
height: fit-content;
/* background-color: #333; */
color: #fff;
text-align: center;
/* line-height: 100px; */
font-size: 20px;
cursor: move;
transition: background-color 0.3s;
}
.floating-bubble:hover {
/* background-color: #555; */
}
.floating-bubble:active {
/* background-color: #777; */
}
</style>