环境
uniapp 小程序中的webview使用jessibuca直播流, 全屏出现拉伸
调试微信小程序内部webview页面方案
能调试,才能解决问题
- http://debugxweb.qq.com/?inspector=true 在微信打开此链接(很多教程都少了这一步,
虽然我也不知道具体作用) - 打开小程序到对应页面,或者直接在微信打开网页 (谷歌游览器不明原因检测不到页面)
- 打开edge, 输入edge://inspect/#devices
- 等待一会就可以调试
思路
- jessibuca 根据解码方式不同,视频可能是video或者canvas,对两者要特殊处理。
- 又因为video在移动端全屏时导致横屏,又要写一套新的样式
- 全屏的逻辑是将轮播主体全屏,然后将容器旋转90度,左右滑动改为上下滑动
代码
结构
<div
class="wrapper"
:class="{ fullScreen: isFull && !henping, henping: henping }"
@touchstart="handleTouchStart"
@touchmove.prevent="handleTouchMove"
@touchend="handleTouchEnd"
>
<div class="contain">
<div class="video-background"></div>
<div class="video">
<!-- <VideoPlayer ref="videoPlayer" :playUrl="'webrtc://video.vnata.cn:9443/remote/play/live/4294982953?secret=608756365a9782abe447659b636e08e5&expire=662baec6'"></VideoPlayer> -->
<VideoPlayer
:isFull="isFull"
@update:isFull="handleIsFullChange"
ref="videoPlayer"
:playUrl="backUrl || currentUrl"
></VideoPlayer>
</div>
<div class="video-background"></div>
</div>
</div>
样式
.wrapper {
height: 50.2336vw;
width: 100%;
overflow: auto;
position: relative;
// 隐藏滚动条
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
&::-webkit-scrollbar {
display: none; /* Chrome, Safari and Opera */
}
.contain {
position: relative;
height: 50.2336vw;
width: 300vw;
overflow-x: auto;
display: flex;
justify-content: center;
}
&.fullScreen {
.contain {
transition: transform 0.1s;
z-index: 9998 !important;
position: absolute !important;
left: 50%;
top: 50%;
transform: translate(-50%, -50%) rotate(90deg) !important;
transform-origin: center center !important;
height: 100vw;
width: 300vh;
overflow: auto;
display: flex;
justify-content: center;
}
.video {
height: 100vw;
width: 100vh;
video {
height: 100vw !important;
// width: 100vh !important;
}
canvas {
position: relative !important;
top: 0 !important;
left: 0 !important;
height: 100vw !important;
width: 100vh !important;
padding: 0 !important;
transform: none !important;
}
}
.video-background {
height: 100vw;
width: 100vh;
}
}
&.henping {
.contain {
z-index: 9998 !important;
position: relative !important;
height: 100vh;
width: 300vw;
overflow: auto;
display: flex;
justify-content: center;
}
.video {
height: 100vh;
width: 100vw;
video {
height: 100vh !important;
// width: 100vh !important;
}
canvas {
position: relative !important;
top: 0 !important;
left: 0 !important;
height: 100vh !important;
// width: 100vw !important;
padding: 0 !important;
transform: none !important;
}
}
.video-background {
height: 100vh;
width: 100vw;
}
}
}
.video {
height: 100%;
width: 100vw;
}
.video-background {
background-color: #4d505c;
height: 100%;
width: 100vw;
}
JS
// 全屏两种情况,横屏与竖屏,因为视频可能是video也可能是canvas
const henping = ref(false)
const handleFullscreenchange = () => {
if (!document.fullscreenElement) {
henping.value = false
isFull.value = false
} else {
if (window.orientation === 90 || window.orientation === -90) {
// 横屏
// 修改your-container的宽高
// 全屏时应用的样式
henping.value = true
// 滚动到中间
setTimeout(() => {
const container = document.querySelector('.wrapper')
container.scrollLeft = container.offsetWidth
}, 100)
} else {
// 竖屏
// 修改your-container的宽高
// 调用播放器的resize()方法
}
isFull.value = true
}
}
onBeforeUnmount(() => {
document.removeEventListener('fullscreenchange', handleFullscreenchange)
})
onMounted(async () => {
// 滚动到中间
const container = document.querySelector('.wrapper')
container.scrollLeft = container.offsetWidth
// 监听全屏状态变化的事件
document.addEventListener('fullscreenchange', handleFullscreenchange)
})
// 全屏
const isFull = ref(false)
const videoPlayer = ref(null)
const fullscreen = () => {
videoPlayer.value.fullscreen()
}
const handleIsFullChange = (newIsFull) => {
isFull.value = newIsFull
}
watch(isFull, async (val) => {
const container = document.querySelector('.contain')
const container2 = document.querySelector('.wrapper')
if (val) {
// js全屏
await container2.requestFullscreen()
if (!henping.value) container.style.top = '50%'
// await window.screen.orientation.lock('portrait') // 锁定为竖屏 无效
} else {
document.exitFullscreen()
container.style.top = '0'
// 滚动到中间
const container2 = document.querySelector('.wrapper')
container2.scrollLeft = container2.offsetWidth
setTimeout(() => {
container.style.top = '0'
// 滚动到中间
const container2 = document.querySelector('.wrapper')
container2.scrollLeft = container2.offsetWidth
}, 100)
}
})
// 滑动切换视频
const startX = ref(0)
const startY = ref(0)
const currentX = ref(0)
const currentY = ref(0)
const isDragging = ref(false)
const isCenter = ref(true)
function handleTouchStart(event) {
// 全屏则是y轴
startY.value = event.touches[0].clientY
startX.value = event.touches[0].clientX
}
function handleTouchMove(event) {
isDragging.value = true
if (isFull.value && !henping.value) {
currentY.value = event.touches[0].clientY
const moveY = currentY.value - startY.value
// const container = document.querySelector('.wrapper')
const container = document.querySelector('.contain')
// container.scrollLeft = container.offsetWidth - moveY
// container.scrollTop = -moveY
container.style.top = `${container.offsetHeight + moveY}px`
return
}
currentX.value = event.touches[0].clientX
const moveX = currentX.value - startX.value
const container = document.querySelector('.wrapper')
container.scrollLeft = container.offsetWidth - moveX
}
function handleTouchEnd() {
if (!isDragging.value) return
isDragging.value = false
if (isFull.value && !henping.value) {
const container = document.querySelector('.contain')
const moveY = currentY.value - startY.value
const threshold = container.offsetHeight / 2
// 回弹逻辑
setTimeout(() => {
container.style.top = '50%'
}, 10)
setTimeout(() => {
container.style.top = '50%'
}, 20)
if (moveY > threshold) {
// 触发切换视频的方法 --上一个
const currentIndex = devicelist.value.findIndex((item) => item.webrtc === currentUrl.value)
if (currentIndex == 0) {
return
}
currentUrl.value = devicelist.value[currentIndex - 1].webrtc
stream_path.value = devicelist.value[currentIndex - 1].stream_path
} else if (moveY < -threshold) {
const currentIndex = devicelist.value.findIndex((item) => item.webrtc === currentUrl.value)
if (currentIndex == devicelist.value.length - 1) {
return
}
currentUrl.value = devicelist.value[currentIndex + 1].webrtc
stream_path.value = devicelist.value[currentIndex + 1].stream_path
}
return
}
const container = document.querySelector('.wrapper')
const containerWidth = container.offsetWidth
const moveX = container.scrollLeft - containerWidth
const threshold = containerWidth / 2
// 回弹逻辑
setTimeout(() => {
container.scrollLeft = containerWidth
}, 100)
setTimeout(() => {
container.scrollLeft = containerWidth
}, 200)
if (moveX < -threshold) {
// 触发切换视频的方法
const currentIndex = devicelist.value.findIndex((item) => item.webrtc === currentUrl.value)
if (currentIndex == 0) {
return
}
currentUrl.value = devicelist.value[currentIndex - 1].webrtc
stream_path.value = devicelist.value[currentIndex - 1].stream_path
} else if (moveX > threshold) {
const currentIndex = devicelist.value.findIndex((item) => item.webrtc === currentUrl.value)
if (currentIndex == devicelist.value.length - 1) {
return
}
currentUrl.value = devicelist.value[currentIndex + 1].webrtc
stream_path.value = devicelist.value[currentIndex + 1].stream_path
}
}