c***@163.com
c***@163.com
  • 发布:2024-03-08 10:52
  • 更新:2024-03-08 10:52
  • 阅读:144

【报Bug】调用createVideoContext的exitFullScreen方法概率触发video的ended事件

分类:uni-app

产品分类: uniapp/小程序/微信

PC开发环境操作系统: Mac

PC开发环境操作系统版本号: Sonoma 14.2.1 (23C71)

第三方开发者工具版本号: 1.06.2401020

基础库版本号: 3.3.4

项目创建方式: CLI

CLI版本号: @vue/cli 5.0.8

示例代码:
<template>  
  <view style="position: relative" @tap="maskTouchend">  

    <video  
        id="video"  
        src="https://sns-video-al.xhscdn.com/stream/110/259/01e5d9a0fe383374010371038dda299acb_259.mp4"  
        style="width: 100%;display: block"  
        :muted="muted"  
        :autoplay="false"  
        :controls="false"  
        :show-mute-btn="false"  
        :show-play-btn="false"  
        :show-center-play-btn="false"  
        :enable-progress-gesture="false"  
        :vslide-gesture-in-fullscreen="false"  
        @play="onPlay"  
        @pause="onPause"  
        @ended="onPlayFinished"  
        @timeupdate="onPlayTimeUpdate"  
        @loadedmetadata="onLoadedData"  
        @fullscreenchange="onFullScreenChange"  
    >  

      <!-- 兼容全屏操作 -->  
      <cover-view v-if="isFullScreen" class="full-screen-back-icon" @tap="toggleFullScreen">  
      </cover-view>  
    </video>  

    <!--  操作区   -->  
    <view :class="{'video-mask' : true,  'video-mask-hide': maskHide}">  
      <view v-if="playStatus === 'init' || playStatus === 'pause'" @tap.stop="play">  
        <uni-icons custom-prefix="iconfont" type="icon-icon_play" size="30" color="#FFFFFF"></uni-icons>  
      </view>  
      <view v-if="playStatus === 'playing'" @tap.stop="pause">  
        <uni-icons custom-prefix="iconfont" type="icon-zanting" size="30" color="#FFFFFF"></uni-icons>  
      </view>  
      <view v-if="playStatus === 'played'" @tap.stop="play">  
        <uni-icons custom-prefix="iconfont" type="icon-zhongbo" size="30" color="#FFFFFF"></uni-icons>  
      </view>  

      <view class="control-bar">  
        <view class="voice" @tap.stop="toggleVoice">  
          <uni-icons custom-prefix="iconfont" :type="muted ? 'icon-jingyin' : 'icon-shengyin'" size="24" color="#FFFFFF"></uni-icons>  
        </view>  
        <view class="progress-bar">  
          <text>{{formatDuration(currentTime)}}</text>  
          <view class="progress-view">  
            <view class="progress" :style="getProgressPercent"></view>  
          </view>  
          <text>{{formatDuration(duration)}}</text>  
        </view>  
        <view class="full-screen" @tap="toggleFullScreen">  
          <uni-icons custom-prefix="iconfont" type="icon-quanping" size="24" color="#FFFFFF"></uni-icons>  
        </view>  
      </view>  
    </view>  

  </view>  
</template>  
<script setup lang="ts">  
import Utils from '../../utils/index'  
import {computed, type Ref, ref, watch} from "vue";  
import {onReady} from "@dcloudio/uni-app";  

const playStatus = ref('init')  
const muted = ref(true)  
const duration = ref(0)  
const currentTime = ref(0)  
const hide = ref(false)  
const ctx: Ref<any> = ref(null)  
const playedPercent = ref(0)  
const isFullScreen = ref(false)  

const touchNum = ref(0)  
let touchTimer: number | null | undefined = null  
const maskTouchend = () => {  
  if(touchTimer) clearTimeout(touchTimer)  
  touchNum.value = touchNum.value + 1  
  touchTimer = setTimeout(()=>{  
    if(touchNum.value == 1){  
      console.log('单击')  
      toggleMaskHide()  
    }  
    if(touchNum.value >= 2){  
      console.log('双击')  
      if(playStatus.value === 'playing') pause()  
      if(playStatus.value === 'pause') play()  
    }  
    touchNum.value = 0  
  },250)  
}  

const maskHide = computed(() => {  
  if(playStatus.value === 'playing'){  
    return !!hide.value;  
  }else{  
    return false  
  }  
})  

onReady(()=>{  
  ctx.value = uni.createVideoContext('video')  
})  

const onLoadedData = (e) => {  
  console.log('onLoadedData', e)  
  duration.value = e.detail.duration  
}  

const onPlay = () => {  
  playStatus.value = 'playing'  
}  
const onPause = () => {  
  playStatus.value = 'pause'  
}  

const onPlayFinished = () => {  
  console.log('完播')  
  playStatus.value = 'played'  
}  

const onPlayTimeUpdate = (e) => {  
  currentTime.value = e.detail.currentTime  
  playedPercent.value = (e.detail.currentTime / e.detail.duration) * 100  
  if(playedPercent.value > 90){  
    console.log('播放进度超过90%', playedPercent.value)  
    //  TODO 提交完播记录  
  }  
}  

const play = () => {  
  ctx.value.play()  
  hide.value = true  
}  

const pause = () => {  
  ctx.value.pause()  
  hide.value = true  
}  

const toggleMaskHide = () => {  
  if(playStatus.value === 'playing'){  
    hide.value = !hide.value  
  }else{  
    hide.value = false  
  }  
}  

const toggleVoice = () => {  
  muted.value = !muted.value  
}  

const toggleFullScreen = () => {  
  if(isFullScreen.value){  
    ctx.value.exitFullScreen()  
  }else{  
    ctx.value.requestFullScreen()  
  }  
}  

const onFullScreenChange = e => {  
  console.log('操作切换全屏',e)  
  isFullScreen.value = e.detail.fullScreen  
}  

const getProgressPercent = () => {  
    return {width: playedPercent + '%'}  
}  

const formatDuration = Utils.formatDuration  

let hideTimer: number | null | undefined=null  
watch(hide, () => {  
  if(!hide.value && playStatus.value === 'playing'){  
    if(hideTimer) clearTimeout(hideTimer)  
    hideTimer = setTimeout(() => {  
      hide.value = true  
    }, 5000)  
  }  
})  
</script>  
<style lang="scss" scoped>  
.video-mask{  
  position: absolute;  
  left: 0;  
  top: 0;  
  right: 0;  
  bottom: 0;  
  background-color: rgba(0,0,0,0.5);  
  z-index: 100;  
  display: flex;  
  align-items: center;  
  justify-content: center;  
  opacity: 1;  
  transition: 0.3s;  
}  
.video-mask-hide{  
  opacity: 0;  
}  
.control-bar{  
  position: absolute;  
  bottom: 0;  
  left: 0;  
  height: 80rpx;  
  width: 100%;  
  background: linear-gradient(180deg,rgba(0,0,0,0),  rgba(0,0,0,1));  
  display: flex;  
  align-items: center;  
  box-sizing: border-box;  
}  

.progress-bar{  
  display: flex;  
  color: #ffffff;  
  flex: 1;  
  align-items: center;  
  font-size: 24rpx;  
}  
.voice,  
.full-screen{  
  width: 100rpx;  
  display: flex;  
  align-items: center;  
  justify-content: center;  
}  
.progress-view{  
  flex: 1;  
  height: 6rpx;  
  background: rgba(255,255,255,0.6);  
  border-radius: 3rpx;  
  margin: 0 20rpx;  

}  
.progress{  
  height: 100%;  
  background: #FFFFFF;  
  border-radius: 3rpx;  

}  

.full-screen-back-icon{  
  position: fixed;  
  left: 0;  
  top: 0;  
  right: 0;  
  bottom: 0;  
  background: rgba(0,0,0,0.2);  
  z-index: 10000;  

}  
</style>  

操作步骤:

调用exitFullScreen方法退出video全屏之后,有一定概率会触发video组件的ended事件

预期结果:

调用exitFullScreen不触发video组件ended事件

实际结果:

调用exitFullScreen概率触发video组件ended事件

bug描述:

通过uni.createVideoContext创建ctx,调用ctx.exitFullScreen方法,video组件的@ended事件有概率会触发。

2024-03-08 10:52 负责人:无 分享
已邀请:

要回复问题请先登录注册