赞
踩
问题:vue3开发嵌入式,播放器在浏览器中是正常的。但嵌入到app里,app不适配,无法全屏,无法设置倍速,controls在视频播放时点击视频无法弹出。
期间试了vue-video-play,vue3-video-play等视频插件,也是相同情况
1.使用了vant图标,先安装vant
2.视频链接,需要自己填
3.引入的useDraggable,就是封装的拖拽js
4.只适合移动端,因为到移动端有些问题,做了样式调整。动作事件也是移动端的
5.template中class类名不要乱改,封装的拖拽js代码里有获取
<template>
<div class="all_box">
<div class="videoBox">
<video ref="videoPlayer"
src=""></video>
</div>
<div class="controlsBox">
<div class="progress-box" @click="onProgress($event)" ref="progressBox">
<div class="progress" :style="{ width: `${progressLength}px` }"></div>
<div ref="draggableDiv" class="it-layout-aside" :style="{ left: `${progressLength}px` }"></div>
</div>
<div class="playBtn" @click="clickPlay()">
<van-icon name="pause-circle-o" size="30" v-if="showPlay" />
<van-icon name="play-circle-o" size="30" v-else />
</div>
<div class="progress-time">{{ timeString }}</div>
<div class="selRate">
<select class="selRate_selet" v-model="selRate" @change="onSelRate()">
<option value=0.5>0.5</option>
<option value=1 selected>1.0</option>
<option value=1.25>1.25</option>
<option value=1.5>1.5</option>
<option value=2>2.0</option>
</select>
</div>
</div>
</div>
</template>
<script setup>
import { ref, unref, } from "vue";
import { useDraggable } from './components/CommentResponse/Use'
const videoPlayer = ref(null);
const progressBox = ref(null)
const showPlay = ref(false)
const progressLength = ref(0)
const timeString = ref('00:00/00:00')
const selRate = ref(1)
//拖动进度条
const moveing = (val) => {
showPlay.value = true;
clearInterval(progressTimer)
var length = val - progressBox.value.offsetLeft
var percent = length / progressBox.value.offsetWidth
unref(videoPlayer).currentTime = percent * unref(videoPlayer).duration
unref(videoPlayer).play()
progressTimer = setInterval(changeProgress, 60)
}
const draggableDiv = useDraggable(moveing)
//倍速
const onSelRate = () => {
unref(videoPlayer).playbackRate = selRate.value
}
//启动|停止
const clickPlay = () => {
if (showPlay.value) {
unref(videoPlayer).pause();
showPlay.value = false;
clearInterval(progressTimer)
} else {
unref(videoPlayer).play();
showPlay.value = true;
progressTimer = setInterval(changeProgress, 60)
}
}
var progressTimer = null // 进度 timer
// 计算时长,注意:这里的 padStart 是 es7 语法
const parseTime = (value) => {
if (!value) return ''
let interval = Math.floor(value)
let minute = (Math.floor(interval / 60)).toString().padStart(2, '0')
let second = (interval % 60).toString().padStart(2, '0')
return `${minute}:${second}`
}
// 推进进度条
const changeProgress = () => {
if (unref(videoPlayer).currentTime && unref(videoPlayer).duration) {
if (parseTime(unref(videoPlayer).currentTime) === parseTime(unref(videoPlayer).duration)) {
progressLength.value = 0;
timeString.value = '00:00/00:00';
showPlay.value = false;
} else {
let timeStr = parseTime(unref(videoPlayer).currentTime) + '/' + parseTime(unref(videoPlayer).duration)
let percent = unref(videoPlayer).currentTime / unref(videoPlayer).duration
progressLength.value = percent * 365;
timeString.value = timeStr;
}
}
}
// 点击进度条的任意地方
const onProgress = (e) => {
showPlay.value = true;
clearInterval(progressTimer)
var length = e.x - progressBox.value.offsetLeft
var percent = length / progressBox.value.offsetWidth
unref(videoPlayer).currentTime = percent * unref(videoPlayer).duration
unref(videoPlayer).play()
progressTimer = setInterval(changeProgress, 60)
}
</script>
<style scoped >
.all_box {
margin: 30px;
}
.it-layout-aside {
position: absolute;
top: -4px;
left: 0px;
width: 13px;
height: 13px;
border-radius: 50%;
background: rgb(0, 0, .5);
opacity: 0.8;
color: #fff;
cursor: move;
opacity: 1;
z-index: 999;
}
video {
width: 100%;
height: 200px;
margin: 0 auto;
position: relative;
}
.controlsBox {
background: #ccc;
height: 50px;
position: relative;
}
.progress-box {
position: relative;
background: rgba(0, 0, 0, 0.1);
border-radius: 8px;
overflow: hidden;
cursor: pointer;
}
.progress {
position: absolute;
top: 0;
left: 0;
width: 0%;
height: 100%;
background: white;
border-radius: 8px 0px 0px 8px;
}
.slider_circle {
position: absolute;
top: 0;
left: 0;
width: 20px;
height: 50px;
background: red;
}
.videoBox {
width: 100%;
min-width: 100%;
max-width: 100%;
height: 200px;
position: relative;
background: black;
}
.progress-box {
width: 365px;
height: 6px;
position: absolute;
bottom: 35px;
right: 1%;
overflow: visible;
}
.playBtn {
width: 30px;
height: 30px;
position: absolute;
bottom: 1px;
left: 10px;
}
.progress-time {
height: 30px;
position: absolute;
bottom: 1px;
left: 50px;
color: #f8f8f8;
display: flex;
align-items: center;
}
.selRate {
width: 70px;
height: 30px;
position: absolute;
bottom: 1px;
left: 140px;
display: flex;
align-items: center;
display: flex;
align-items: center;
justify-content: center;
}
.selRate_selet{
height: 20px;
width: 60px;
}
i {
font-size: 40px;
color: white;
}
</style>
import { ref, unref, onMounted, onUnmounted } from "vue";
export const useDraggable = (moveing) => {
// 声明一个 ref,用于存储 div 元素的引用
const divRef = ref(null)
// 声明一些变量,用于存储鼠标或触摸位置以及拖拽状态
let offsetX = 0 // 鼠标点击或触摸点距离 div 左侧的偏移
let offsetY = 0 // 鼠标点击或触摸点距离 div 顶部的偏移
let isDragging = false // 是否正在拖拽中
// 禁用页面滚动的函数
const disablePageScroll = () => {
document.body.style.overflow = 'hidden'
}
// 启用页面滚动的函数
const enablePageScroll = () => {
document.body.style.overflow = 'auto'
}
// 开始拖拽,禁用页面滚动
const startDragging = () => {
isDragging = true
disablePageScroll()
}
// 停止拖拽,启用页面滚动,并稍后重新启用点击事件
const stopDragging = () => {
isDragging = false
enablePageScroll()
setTimeout(() => {
if (divRef.value) {
divRef.value.style.pointerEvents = 'auto'
}
}, 100)
}
// 处理鼠标移动或触摸移动事件
const handleMouseMove = (event) => {
requestAnimationFrame(() => {
if (isDragging && divRef.value) {
const clientX = 'touches' in event ? event.touches[0].clientX : event.clientX
const clientY = 'touches' in event ? event.touches[0].clientY : event.clientY
const x = clientX - offsetX
const y = clientY - offsetY
// 阻止事件传播,避免干扰正常滚动
event.stopPropagation()
event.preventDefault()
// 获取浏览器窗口的最大可视区域宽度和高度
// const maxX = window.innerWidth - (divRef.value.clientWidth || 0)
const maxX = 360 - (divRef.value.clientWidth || 0)
const maxY = window.innerHeight - (divRef.value.clientHeight || 0)
// 设置 div 的位置,确保不超出窗口范围
divRef.value.style.left = `${Math.min(maxX, Math.max(0, x))}px`
// divRef.value.style.top = `${Math.min(maxY, Math.max(0, y))}px`
divRef.value.style.top = `-4px`
// 禁用 div 上的点击事件,以避免拖拽时触发点击事件
divRef.value.style.pointerEvents = 'none'
const tiao = document.querySelector('.progress')
tiao.style.width = `${Math.min(maxX, Math.max(0, x))}px`
// console.log(tiao.style, 111)
//回调宽度
moveing(Math.min(maxX, Math.max(0, x)))
}
})
}
// 处理鼠标松开或触摸结束事件
const handleMouseUp = () => {
// 停止拖拽,恢复点击事件
stopDragging()
// 移除鼠标移动事件和触摸移动事件的监听器
document.removeEventListener('touchmove', handleMouseMove)
document.removeEventListener('mousemove', handleMouseMove)
}
// 处理鼠标按下或触摸开始事件
const handleMouseDown = (event) => {
if (!divRef.value) return
// 获取鼠标点击或触摸点相对于 div 左侧和顶部的偏移
offsetX = 'touches' in event ? event.touches[0].clientX - divRef.value.offsetLeft : event.clientX - divRef.value.offsetLeft
offsetY = 'touches' in event ? event.touches[0].clientY - divRef.value.offsetTop : event.clientY - divRef.value.offsetTop
// 开始拖拽,添加鼠标移动和触摸移动事件监听器
startDragging()
document.addEventListener('mousemove', handleMouseMove, {
passive: false, // 阻止默认滚动行为
})
document.addEventListener('touchmove', handleMouseMove, {
passive: false, // 阻止默认滚动行为
})
// 添加鼠标松开和触摸结束事件监听器
document.addEventListener('mouseup', handleMouseUp)
document.addEventListener('touchend', handleMouseUp)
}
// 在组件挂载时,添加鼠标按下和触摸开始事件监听器
onMounted(() => {
if (divRef.value) {
divRef.value.addEventListener('mousedown', handleMouseDown)
divRef.value.addEventListener('touchstart', handleMouseDown)
}
})
// 在组件卸载时,移除事件监听器
onUnmounted(() => {
if (divRef.value) {
divRef.value.removeEventListener('mousedown', handleMouseDown)
divRef.value.removeEventListener('touchstart', handleMouseDown)
}
document.removeEventListener('mouseup', handleMouseUp)
document.removeEventListener('touchend', handleMouseUp)
})
// 返回 div 元素的引用,可以在组件中使用该引用来创建可拖拽的元素
return divRef
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。