h5移动端实现视频手动全屏,以及左右滑动切换视频。附带调试微信小程序内部webview页面方案

环境

uniapp 小程序中的webview使用jessibuca直播流, 全屏出现拉伸

调试微信小程序内部webview页面方案

能调试,才能解决问题

  1. http://debugxweb.qq.com/?inspector=true 在微信打开此链接(很多教程都少了这一步,虽然我也不知道具体作用
  2. 打开小程序到对应页面,或者直接在微信打开网页 (谷歌游览器不明原因检测不到页面)
  3. 打开edge, 输入edge://inspect/#devices
  4. 等待一会就可以调试
    在这里插入图片描述

思路

  • 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
  }
}
  • 10
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值