From 7875d64f525de4705312e00fd2391e3fbc43d9b5 Mon Sep 17 00:00:00 2001
From: zjk <852185829@qq.com>
Date: 星期二, 29 九月 2026 14:06:46 +0800
Subject: [PATCH] fix(course-detail): 修复H5视频自动播放拦截与openinstall课程ID问题
---
traditionalApp/pages/courseDetail/courseDetail.vue | 61 +++++++++++++++++++++++++-----
1 files changed, 51 insertions(+), 10 deletions(-)
diff --git a/traditionalApp/pages/courseDetail/courseDetail.vue b/traditionalApp/pages/courseDetail/courseDetail.vue
index f1de5af..13f206f 100644
--- a/traditionalApp/pages/courseDetail/courseDetail.vue
+++ b/traditionalApp/pages/courseDetail/courseDetail.vue
@@ -20,7 +20,7 @@
<wd-watermark v-if="videoWatermarkText" class="video-watermark" :content="videoWatermarkText"
:full-screen="false" :width="160" :height="110" :gutter-x="36" :gutter-y="36" :size="15"
color="rgba(255, 255, 255, 0.24)" :rotate="-18" :opacity="1" :z-index="2" />
- <view v-if="showPlaybackRetry" class="video-retry-mask" @tap.stop="retryPlayback">
+ <view v-if="showPlaybackRetry" class="video-retry-mask" @tap.stop="retryPlayback(true)">
<text class="video-retry-text">点击开始播放</text>
</view>
</view>
@@ -885,7 +885,8 @@
// return
// }
if (canPlayVideo(item)) {
- playSelectedVideo(item)
+ // 点击章节属于用户手势,需透传给播放逻辑,否则 H5 会被浏览器自动播放策略拦截
+ playSelectedVideo(item, true)
return
}
handlePaidVideoTap(item)
@@ -893,13 +894,14 @@
/**
* 切换顶部播放器到指定小节,并在可自动播放的环境中立即开始播放。
+ * @param fromUserGesture 是否由用户点击章节触发,H5 需要借助该手势放行自动播放
*/
- async function playSelectedVideo(item : CourseVideo) {
+ async function playSelectedVideo(item : CourseVideo, fromUserGesture = false) {
if (!canPlayVideo(item)) {
return
}
if (activeVideoId.value === item.id && showVideoPlayer.value) {
- retryPlayback()
+ retryPlayback(fromUserGesture)
return
}
activeVideoId.value = item.id
@@ -907,7 +909,7 @@
resetVideoPlaybackFlags()
await nextTick()
initVideoContext()
- retryPlayback()
+ retryPlayback(fromUserGesture)
}
/**
@@ -960,13 +962,52 @@
}
/**
- * 对当前播放器执行播放重试,避免首次切换章节时无感失败。
+ * H5 下取出播放器内部的原生 video 节点。
+ * uni 的 videoContext.play() 在 H5 下拿不到 Promise,无法感知“被浏览器拦截”的情况,这里直接操作原生节点。
*/
- function retryPlayback() {
- if (isReadonlyDisplayMode) {
+ function resolveNativeVideoElement() {
+ // #ifdef H5
+ const container = document.getElementById(VIDEO_PLAYER_ID)
+ if (!container) {
+ return null
+ }
+ // id 可能挂在播放器外层节点上,也可能直接落在原生 video 节点上,两种结构都兼容
+ if (container instanceof HTMLVideoElement) {
+ return container
+ }
+ return container.querySelector('video')
+ // #endif
+ return null
+ }
+
+ /**
+ * 对当前播放器执行播放重试,避免首次切换章节时无感失败。
+ * @param fromUserGesture 是否由用户点击触发:H5 有自动播放限制,只有用户手势内调用 play 才可靠
+ */
+ function retryPlayback(fromUserGesture = false) {
+ // H5 下非用户手势触发的自动播放会被浏览器拦截,这里直接跳过;点击章节或遮罩属于用户手势,需要真正执行
+ if (isReadonlyDisplayMode && !fromUserGesture) {
return
}
- if (!videoContext || !currentVideoUrl.value) {
+ if (!currentVideoUrl.value) {
+ return
+ }
+ if (isReadonlyDisplayMode) {
+ const nativeVideo = resolveNativeVideoElement()
+ if (!nativeVideo) {
+ playbackFailed.value = true
+ return
+ }
+ const playPromise = nativeVideo.play()
+ if (playPromise) {
+ // 播放被拦截(如非用户手势)时展示“点击开始播放”遮罩兜底
+ playPromise.catch(() => {
+ playbackFailed.value = true
+ })
+ }
+ return
+ }
+ if (!videoContext) {
return
}
try {
@@ -1082,7 +1123,7 @@
}
const openinstallOpened = await wakeupOrInstallByOpeninstall({
page: 'courseDetail',
- courseId: String(resolveCurrentCourseId() || '').trim()
+ courseId: String(resolveShareCourseId() || '').trim()
})
if (openinstallOpened) {
return
--
Gitblit v1.7.1