hookehuyr

fix(视频播放器): 修复视频封面缺失时的背景显示问题

在视频封面缺失时,播放器区域显示为透明背景,导致视觉不一致。为 VideoPlayer 组件添加黑色背景,并在 StudyDetailPage 中动态设置封面容器的背景色:有封面时透明,无封面时黑色。同时优化 useVideoPlayer 配置逻辑,避免传递空的 poster 属性。
...@@ -196,6 +196,7 @@ defineExpose({ ...@@ -196,6 +196,7 @@ defineExpose({
196 height: 100%; 196 height: 100%;
197 display: block; 197 display: block;
198 aspect-ratio: 16/9; 198 aspect-ratio: 16/9;
199 + background-color: #000;
199 } 200 }
200 201
201 .video-player.loading { 202 .video-player.loading {
......
...@@ -276,42 +276,48 @@ export function useVideoPlayer(props, emit, videoRef, nativeVideoRef) { ...@@ -276,42 +276,48 @@ export function useVideoPlayer(props, emit, videoRef, nativeVideoRef) {
276 return !canPlayHlsNatively(); 276 return !canPlayHlsNatively();
277 }); 277 });
278 278
279 - const videoOptions = computed(() => ({ 279 + const videoOptions = computed(() => {
280 - controls: true, 280 + const base = {
281 - preload: "metadata", 281 + controls: true,
282 - responsive: true, 282 + preload: "metadata",
283 - autoplay: props.autoplay, 283 + responsive: true,
284 - playsinline: true, 284 + autoplay: props.autoplay,
285 - playbackRates: [0.5, 0.75, 1, 1.25, 1.5, 2], 285 + playsinline: true,
286 - sources: videoSources.value, 286 + playbackRates: [0.5, 0.75, 1, 1.25, 1.5, 2],
287 - html5: { 287 + sources: videoSources.value,
288 - vhs: { 288 + html5: {
289 - overrideNative: shouldOverrideNativeHls.value, 289 + vhs: {
290 + overrideNative: shouldOverrideNativeHls.value,
291 + },
292 + nativeVideoTracks: false,
293 + nativeAudioTracks: false,
294 + nativeTextTracks: false,
295 + hls: {
296 + withCredentials: false
297 + }
290 }, 298 },
291 - nativeVideoTracks: false, 299 + techOrder: ['html5'],
292 - nativeAudioTracks: false, 300 + userActions: {
293 - nativeTextTracks: false, 301 + hotkeys: true,
294 - hls: { 302 + doubleClick: true,
295 - withCredentials: false 303 + },
296 - } 304 + controlBar: {
297 - }, 305 + progressControl: {
298 - techOrder: ['html5'], 306 + seekBar: {
299 - userActions: { 307 + mouseTimeDisplay: {
300 - hotkeys: true, 308 + keepTooltipsInside: true,
301 - doubleClick: true, 309 + },
302 - },
303 - controlBar: {
304 - progressControl: {
305 - seekBar: {
306 - mouseTimeDisplay: {
307 - keepTooltipsInside: true,
308 }, 310 },
309 }, 311 },
310 }, 312 },
311 - }, 313 + ...props.options,
312 - ...props.options, 314 + errorDisplay: false,
313 - errorDisplay: false, 315 + };
314 - })); 316 + if (!base.poster) {
317 + delete base.poster;
318 + }
319 + return base;
320 + });
315 321
316 // 8. Video.js 挂载处理 322 // 8. Video.js 挂载处理
317 const handleVideoJsMounted = (payload) => { 323 const handleVideoJsMounted = (payload) => {
......
...@@ -10,8 +10,8 @@ ...@@ -10,8 +10,8 @@
10 <!-- 视频播放区域 --> 10 <!-- 视频播放区域 -->
11 <div v-if="course.course_type === 'video'" class="w-full relative"> 11 <div v-if="course.course_type === 'video'" class="w-full relative">
12 <!-- 视频封面和播放按钮 --> 12 <!-- 视频封面和播放按钮 -->
13 - <div v-if="!isPlaying" class="relative w-full" style="aspect-ratio: 16/9;"> 13 + <div v-if="!isPlaying" class="relative w-full" :style="{ aspectRatio: '16/9', backgroundColor: courseFile.cover ? 'transparent' : '#000' }">
14 - <img :src="courseFile.cover" :alt="course.title" class="w-full h-full object-cover" /> 14 + <img v-if="courseFile.cover" :src="courseFile.cover" :alt="course.title" class="w-full h-full object-cover" />
15 <div class="absolute inset-0 flex items-center justify-center cursor-pointer" 15 <div class="absolute inset-0 flex items-center justify-center cursor-pointer"
16 @click="startPlay"> 16 @click="startPlay">
17 <div 17 <div
......