liveh5-nuxt/app/components/liveMinWindow/index.vue
xingyy 3c69236caa feat(live): 实现直播间最小化窗口功能
- 新增最小化窗口组件 liveMinWindow
- 在 liveRoom 页面中集成最小化窗口功能
- 优化 liveStore,增加相关状态和方法支持最小化窗口
- 调整
2025-02-11 14:55:25 +08:00

189 lines
4.8 KiB
Vue

<template>
<div ref="dragRef"
:style="style"
class="fixed rounded-5px overflow-hidden shadow-lg cursor-move z-50"
@mousedown.stop="handleDragStart"
@touchstart.stop="handleDragStart">
<div class="relative">
<img :src="props.snapshot"
class="w-80px object-cover"
alt="直播画面">
<div class="absolute inset-0 bg-black/40 flex items-center justify-center"
@click.stop="handleClick">
<span class="text-white text-12px">点击回到直播</span>
</div>
<button @click.stop="handleClose"
class="absolute top-10px right-10px text-white bg-black/40 rounded-full w-5 h-5 flex items-center justify-center hover:bg-black/60 cursor-pointer">
<van-icon name="cross" />
</button>
</div>
</div>
</template>
<script setup>
import { ref, computed, onBeforeUnmount, shallowRef, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { useThrottleFn } from '@vueuse/core'
const props = defineProps({
snapshot: {
type: String,
required: true
},
onClose: {
type: Function,
default: () => {}
},
initialPosition: {
type: Object,
default: () => ({
top: '80px',
right: '16px'
})
}
})
const router = useRouter()
const dragRef = shallowRef(null)
// 拖动相关状态
const isDragging = ref(false)
const startX = ref(0)
const startY = ref(0)
const left = ref(0)
const top = ref(0)
// 初始化位置
onMounted(() => {
const rect = dragRef.value.getBoundingClientRect()
// 将 right 值转换为 left 值
left.value = window.innerWidth - rect.width - parseInt(props.initialPosition.right)
top.value = parseInt(props.initialPosition.top)
})
// 计算样式
const style = computed(() => ({
left: left.value ? `${left.value}px` : 'auto',
top: top.value ? `${top.value}px` : 'auto',
right: !left.value ? props.initialPosition.right : 'auto',
transition: isDragging.value ? 'none' : 'all 0.3s ease',
}))
// 开始拖动
const handleDragStart = (event) => {
event.stopPropagation()
isDragging.value = true
const point = event.touches ? event.touches[0] : event
// 获取元素当前位置
const rect = dragRef.value.getBoundingClientRect()
left.value = rect.left
top.value = rect.top
// 记录起始点击位置
startX.value = point.clientX - left.value
startY.value = point.clientY - top.value
if (event.type === 'mousedown') {
document.addEventListener('mousemove', handleDragMove)
document.addEventListener('mouseup', handleDragEnd)
} else {
document.addEventListener('touchmove', handleDragMove, { passive: false })
document.addEventListener('touchend', handleDragEnd)
}
}
// 拖动中
const handleDragMove = useThrottleFn((event) => {
if (!isDragging.value) return
event.preventDefault()
event.stopPropagation()
const point = event.touches ? event.touches[0] : event
const rect = dragRef.value.getBoundingClientRect()
const maxX = window.innerWidth - rect.width
const maxY = window.innerHeight - rect.height
left.value = Math.min(Math.max(0, point.clientX - startX.value), maxX)
top.value = Math.min(Math.max(0, point.clientY - startY.value), maxY)
}, 16)
// 添加防抖处理边缘吸附
const handleEdgeSnap = useThrottleFn(() => {
const rect = dragRef.value.getBoundingClientRect()
const centerX = rect.left + rect.width / 2
left.value = centerX > window.innerWidth / 2
? window.innerWidth - rect.width - 16
: 16
}, 100)
// 结束拖动
const handleDragEnd = () => {
if (!isDragging.value) return
isDragging.value = false
handleEdgeSnap()
document.removeEventListener('mousemove', handleDragMove)
document.removeEventListener('mouseup', handleDragEnd)
document.removeEventListener('touchmove', handleDragMove)
document.removeEventListener('touchend', handleDragEnd)
}
// 处理点击事件
const handleClick = (event) => {
event.stopPropagation()
if (!isDragging.value) {
handleReturnLive()
}
}
const handleReturnLive = () => {
router.push('/')
props.onClose()
}
const handleClose = (event) => {
event?.stopPropagation()
props.onClose()
}
onBeforeUnmount(() => {
document.removeEventListener('mousemove', handleDragMove)
document.removeEventListener('mouseup', handleDragEnd)
document.removeEventListener('touchmove', handleDragMove)
document.removeEventListener('touchend', handleDragEnd)
})
</script>
<style scoped>
.fixed {
will-change: transform, opacity;
touch-action: none;
-webkit-user-select: none;
user-select: none;
transform: translateZ(0); /* 开启GPU加速 */
}
/* 添加动画类 */
.min-window-enter-active,
.min-window-leave-active {
transition: transform 0.3s ease, opacity 0.3s ease;
}
.min-window-enter-from,
.min-window-leave-to {
transform: translateY(100%);
opacity: 0;
}
img {
pointer-events: none;
-webkit-user-drag: none;
user-drag: none;
}
</style>