liveh5-nuxt/app/components/floatingVideo/index.vue
xingyy 86198811aa feat(live): 优化直播间功能并添加画中画支持
- 更新直播源地址
- 添加画中画功能,支持视频拖动和缩放
- 实现直播加密密钥生成和数据解密
- 优化直播房间组件,支持全屏和缩略图模式
- 新增日志发送接口
2025-02-11 11:34:24 +08:00

207 lines
4.8 KiB
Vue

<template>
<div
v-show="isVisible"
:class="['floating-video', { minimized: isMinimized }]"
class="!aspect-video"
:style="[positionStyle, containerStyle]"
@touchstart.prevent="handleTouchStart"
@touchmove.prevent="handleTouchMove"
@touchend="handleTouchEnd"
>
<video
ref="videoRef"
class="video-player "
controls
@loadedmetadata="handleVideoMetadata"
>
<source src="@/static/video/example.mp4" type="video/mp4" />
您的浏览器不支持 HTML5 视频。
</video>
<div class="control-bar">
<div class="minimize-btn" @click="toggleMinimize">
<span v-if="isMinimized">⤢</span>
<span v-else>⤓</span>
</div>
<div class="close-btn" @click="closeVideo"></div>
</div>
</div>
</template>
<script setup>
import { ref, computed, onMounted, onBeforeUnmount } from 'vue'
const props = defineProps({
isVisible: {
type: Boolean,
default: false
}
})
const emit = defineEmits(['close'])
const videoRef = ref(null)
const aspectRatio = ref(16 / 9) // 默认宽高比
const isMinimized = ref(false)
const position = ref({ x: 20, y: 20 })
const isDragging = ref(false)
const dragStart = ref({ x: 0, y: 0 })
// 初始化窗口尺寸为0
const windowSize = ref({
width: 0,
height: 0
})
const handleVideoMetadata = () => {
const video = videoRef.value
if (video.videoWidth && video.videoHeight) {
aspectRatio.value = video.videoWidth / video.videoHeight
}
}
const containerDimensions = computed(() => {
const baseWidth = isMinimized.value ? 150 : 300
const height = baseWidth / aspectRatio.value
return { width: baseWidth, height }
})
const containerStyle = computed(() => {
return {
width: `${containerDimensions.value.width}px`,
height: `${containerDimensions.value.height}px`
}
})
const positionStyle = computed(() => ({
transform: `translate3d(${position.value.x}px, ${position.value.y}px, 0)`
}))
const handleTouchStart = (event) => {
isDragging.value = true
const touch = event.touches[0]
dragStart.value = {
x: touch.clientX - position.value.x,
y: touch.clientY - position.value.y
}
}
const handleTouchMove = (event) => {
if (!isDragging.value) return
const touch = event.touches[0]
let newX = touch.clientX - dragStart.value.x
let newY = touch.clientY - dragStart.value.y
// 添加边界检测
const maxX = windowSize.value.width - containerDimensions.value.width
const maxY = windowSize.value.height - containerDimensions.value.height
newX = Math.max(0, Math.min(newX, maxX))
newY = Math.max(0, Math.min(newY, maxY))
requestAnimationFrame(() => {
position.value = { x: newX, y: newY }
})
}
const handleTouchEnd = () => {
isDragging.value = false
}
const toggleMinimize = () => {
isMinimized.value = !isMinimized.value
const maxX = windowSize.value.width - containerDimensions.value.width
const maxY = windowSize.value.height - containerDimensions.value.height
position.value = {
x: Math.max(0, Math.min(position.value.x, maxX)),
y: Math.max(0, Math.min(position.value.y, maxY))
}
}
const closeVideo = () => {
emit('close')
}
const handleResize = () => {
windowSize.value = {
width: window.innerWidth,
height: window.innerHeight
}
const maxX = windowSize.value.width - containerDimensions.value.width
const maxY = windowSize.value.height - containerDimensions.value.height
position.value = {
x: Math.max(0, Math.min(position.value.x, maxX)),
y: Math.max(0, Math.min(position.value.y, maxY))
}
}
// 在组件挂载后初始化窗口尺寸和事件监听
onMounted(() => {
// 初始化窗口尺寸
windowSize.value = {
width: window.innerWidth,
height: window.innerHeight
}
window.addEventListener('resize', handleResize)
})
onBeforeUnmount(() => {
window.removeEventListener('resize', handleResize)
})
</script>
<style scoped>
/* 样式部分保持不变 */
.floating-video {
position: fixed;
z-index: 1000;
background: #000;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
transition: width 0.3s ease, height 0.3s ease;
overflow: hidden;
transform: translate3d(0, 0, 0);
will-change: transform;
touch-action: none;
}
.video-player {
width: 100%;
height: 100%;
object-fit: fill!important;
}
.control-bar {
position: absolute;
top: 0;
right: 0;
display: flex;
gap: 8px;
padding: 8px;
background: linear-gradient(to bottom, rgba(0, 0, 0, 0.5), transparent);
}
.minimize-btn,
.close-btn {
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
background: rgba(255, 255, 255, 0.2);
border-radius: 50%;
cursor: pointer;
color: white;
font-size: 14px;
}
.minimize-btn:hover,
.close-btn:hover {
background: rgba(255, 255, 255, 0.3);
}
</style>