fix(视频播放器): 修复视频播放器初始化及播放逻辑问题
确保视频播放器组件完全初始化后再执行播放操作 增加播放失败时的错误处理和静音播放重试逻辑 添加调试日志帮助追踪播放流程
Showing
2 changed files
with
65 additions
and
5 deletions
| ... | @@ -113,6 +113,8 @@ const videoOptions = computed(() => ({ | ... | @@ -113,6 +113,8 @@ const videoOptions = computed(() => ({ |
| 113 | })); | 113 | })); |
| 114 | 114 | ||
| 115 | const handleMounted = (payload) => { | 115 | const handleMounted = (payload) => { |
| 116 | + console.log('VideoPlayer: handleMounted 被调用'); | ||
| 117 | + console.log('VideoPlayer: payload.player:', payload.player); | ||
| 116 | state.value = payload.state; | 118 | state.value = payload.state; |
| 117 | player.value = payload.player; | 119 | player.value = payload.player; |
| 118 | if (player.value) { | 120 | if (player.value) { |
| ... | @@ -259,14 +261,60 @@ defineExpose({ | ... | @@ -259,14 +261,60 @@ defineExpose({ |
| 259 | } | 261 | } |
| 260 | }, | 262 | }, |
| 261 | play() { | 263 | play() { |
| 262 | - if (player.value && !player.value.isDisposed && typeof player.value.isDisposed === 'function' && !player.value.isDisposed()) { | 264 | + console.log('VideoPlayer: play() 被调用'); |
| 265 | + console.log('VideoPlayer: player.value:', player.value); | ||
| 266 | + console.log('VideoPlayer: player.value?.isDisposed:', player.value?.isDisposed); | ||
| 267 | + | ||
| 268 | + if (!player.value) { | ||
| 269 | + console.error('VideoPlayer: player.value 不存在,播放器可能还没初始化'); | ||
| 270 | + return; | ||
| 271 | + } | ||
| 272 | + | ||
| 273 | + if (!player.value.isDisposed || typeof player.value.isDisposed !== 'function') { | ||
| 274 | + console.error('VideoPlayer: isDisposed 方法不存在'); | ||
| 275 | + return; | ||
| 276 | + } | ||
| 277 | + | ||
| 278 | + if (player.value.isDisposed()) { | ||
| 279 | + console.error('VideoPlayer: 播放器已被销毁'); | ||
| 280 | + return; | ||
| 281 | + } | ||
| 282 | + | ||
| 283 | + console.log('VideoPlayer: 尝试播放视频'); | ||
| 284 | + | ||
| 285 | + // 检查视频元素状态 | ||
| 263 | try { | 286 | try { |
| 264 | - player.value?.play(); | 287 | + const tech = player.value.tech(true); |
| 265 | - emit('onPlay', player.value); | 288 | + if (tech && tech.el) { |
| 289 | + const videoEl = tech.el(); | ||
| 290 | + console.log('VideoPlayer: videoEl.readyState:', videoEl?.readyState, '(0=HAVE_NOTHING, 1=HAVE_METADATA, 2=HAVE_CURRENT_DATA, 3=HAVE_FUTURE_DATA, 4=HAVE_ENOUGH_DATA)'); | ||
| 291 | + console.log('VideoPlayer: videoEl.paused:', videoEl?.paused); | ||
| 292 | + console.log('VideoPlayer: videoEl.duration:', videoEl?.duration); | ||
| 293 | + console.log('VideoPlayer: videoEl.src:', videoEl?.src); | ||
| 294 | + } | ||
| 266 | } catch (e) { | 295 | } catch (e) { |
| 267 | - console.warn('Video play error:', e); | 296 | + console.warn('VideoPlayer: 无法获取video元素:', e); |
| 268 | } | 297 | } |
| 298 | + | ||
| 299 | + player.value.play() | ||
| 300 | + .then(() => { | ||
| 301 | + console.log('VideoPlayer: play() 成功'); | ||
| 302 | + }) | ||
| 303 | + .catch(error => { | ||
| 304 | + console.error('VideoPlayer: play() 失败:', error.name, error.message); | ||
| 305 | + // 如果是因为自动播放策略失败,可以静音重试 | ||
| 306 | + if (error.name === 'NotAllowedError') { | ||
| 307 | + console.log('VideoPlayer: 浏览器阻止自动播放,尝试静音播放'); | ||
| 308 | + player.value.muted(true); | ||
| 309 | + player.value.play() | ||
| 310 | + .then(() => { | ||
| 311 | + console.log('VideoPlayer: 静音播放成功'); | ||
| 312 | + }) | ||
| 313 | + .catch(err => { | ||
| 314 | + console.error('VideoPlayer: 静音播放也失败:', err); | ||
| 315 | + }); | ||
| 269 | } | 316 | } |
| 317 | + }); | ||
| 270 | }, | 318 | }, |
| 271 | getPlayer() { | 319 | getPlayer() { |
| 272 | return player.value; | 320 | return player.value; | ... | ... |
| ... | @@ -22,7 +22,7 @@ | ... | @@ -22,7 +22,7 @@ |
| 22 | </div> | 22 | </div> |
| 23 | </div> | 23 | </div> |
| 24 | <!-- 视频播放器 --> | 24 | <!-- 视频播放器 --> |
| 25 | - <VideoPlayer v-show="isPlaying" ref="videoPlayerRef" | 25 | + <VideoPlayer v-if="isPlaying" ref="videoPlayerRef" |
| 26 | :video-url="courseFile?.list?.length ? courseFile['list'][0]['url'] : ''" :autoplay="false" | 26 | :video-url="courseFile?.list?.length ? courseFile['list'][0]['url'] : ''" :autoplay="false" |
| 27 | :video-id="courseFile?.list?.length ? courseFile['list'][0]['meta_id'] : ''" | 27 | :video-id="courseFile?.list?.length ? courseFile['list'][0]['meta_id'] : ''" |
| 28 | @onPlay="handleVideoPlay" @onPause="handleVideoPause" /> | 28 | @onPlay="handleVideoPlay" @onPause="handleVideoPause" /> |
| ... | @@ -307,11 +307,23 @@ const course_type_maps = ref({ | ... | @@ -307,11 +307,23 @@ const course_type_maps = ref({ |
| 307 | 307 | ||
| 308 | // 开始播放视频 | 308 | // 开始播放视频 |
| 309 | const startPlay = async () => { | 309 | const startPlay = async () => { |
| 310 | + console.log('StudyDetailPage: startPlay 被调用'); | ||
| 310 | isPlaying.value = true; | 311 | isPlaying.value = true; |
| 312 | + | ||
| 313 | + // 等待 VideoPlayer 组件挂载并初始化完成 | ||
| 311 | await nextTick(); | 314 | await nextTick(); |
| 315 | + | ||
| 316 | + // 需要额外等待 VideoPlayer 组件的 handleMounted 完成 | ||
| 317 | + // 使用 setTimeout 确保播放器已经初始化 | ||
| 318 | + setTimeout(() => { | ||
| 319 | + console.log('StudyDetailPage: videoPlayerRef.value:', videoPlayerRef.value); | ||
| 320 | + console.log('StudyDetailPage: typeof videoPlayerRef.value?.play:', typeof videoPlayerRef.value?.play); | ||
| 312 | if (videoPlayerRef.value) { | 321 | if (videoPlayerRef.value) { |
| 313 | videoPlayerRef.value.play(); | 322 | videoPlayerRef.value.play(); |
| 323 | + } else { | ||
| 324 | + console.error('StudyDetailPage: videoPlayerRef.value 不存在'); | ||
| 314 | } | 325 | } |
| 326 | + }, 300); // 增加延迟,确保播放器初始化完成 | ||
| 315 | }; | 327 | }; |
| 316 | 328 | ||
| 317 | // 处理视频播放状态 | 329 | // 处理视频播放状态 | ... | ... |
-
Please register or login to post a comment