liveh5-nuxt/app/components/floating2/index.vue
xingyy 4d358d130b feat(components): 添加浮动气泡组件并优化直播相关页面
- 在首页引入 FloatingBubble 组件
- 移除 liveRoom 页面的 SideButton 组件中的拖动功能
- 在 liveRoom 页面中使用 floating2 组件包裹 SideButton
- 优化 signature 页面布局
- 在 nuxt.config.js 中启用 vscode 配置
2025-03-05 19:59:48 +08:00

94 lines
2.1 KiB
Vue

<template>
<div
ref="bubbleRef"
class="floating-bubble"
:style="bubbleStyle"
@touchstart="onTouchStart"
@touchmove="onTouchMove"
@touchend="onTouchEnd"
>
<slot></slot>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
import { useThrottleFn } from '@vueuse/core'
const props = defineProps({
offset: {
type: Number,
default: 0
}
})
const bubbleRef = ref(null)
const position = ref({
right: props.offset,
bottom: 100
})
let startTouch = { x: 0, y: 0 }
let startPos = { right: 0, bottom: 0 }
let isDragging = false
const bubbleStyle = computed(() => ({
position: 'fixed',
right: `${position.value.right}px`,
bottom: `${position.value.bottom}px`,
zIndex: 99999,
transition: isDragging ? 'none' : 'all 0.3s'
}))
const onTouchStart = (event) => {
isDragging = true
const touch = event.touches[0]
startTouch = { x: touch.clientX, y: touch.clientY }
startPos = { ...position.value }
}
const onTouchMove = useThrottleFn((event) => {
if (!isDragging) return
event.preventDefault()
const touch = event.touches[0]
const { clientWidth, clientHeight } = document.documentElement
const rect = bubbleRef.value.getBoundingClientRect()
// 计算新位置
const deltaX = startTouch.x - touch.clientX
const deltaY = startTouch.y - touch.clientY
const newRight = startPos.right + deltaX
const newBottom = startPos.bottom + deltaY
// 边界检测
position.value = {
right: Math.min(Math.max(newRight, props.offset),
clientWidth - rect.width - props.offset),
bottom: Math.min(Math.max(newBottom, props.offset),
clientHeight - rect.height - props.offset)
}
}, 16)
const onTouchEnd = () => {
if (!isDragging) return
isDragging = false
const { clientWidth } = document.documentElement
const rect = bubbleRef.value.getBoundingClientRect()
const left = clientWidth - position.value.right - rect.width
// 吸附
position.value.right = left < clientWidth / 2
? clientWidth - rect.width - props.offset
: props.offset
}
</script>
<style scoped>
.floating-bubble {
touch-action: none;
user-select: none;
}
</style>