feat(播放器): 实现音视频互斥播放功能并优化默认封面
在VideoPlayer和AudioPlayer组件中添加互斥播放逻辑,当播放视频时自动暂停音频,反之亦然 为音频播放器添加默认封面图片 更新所有测试图片和音频资源URL为正式CDN地址 添加组件卸载时的清理逻辑
Showing
3 changed files
with
29 additions
and
5 deletions
| 1 | <!-- | 1 | <!-- |
| 2 | * @Date: 2025-04-07 12:35:35 | 2 | * @Date: 2025-04-07 12:35:35 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2025-05-16 16:50:23 | 4 | + * @LastEditTime: 2025-05-30 15:26:15 |
| 5 | * @FilePath: /mlaj/src/components/ui/AudioPlayer.vue | 5 | * @FilePath: /mlaj/src/components/ui/AudioPlayer.vue |
| 6 | * @Description: 音频播放器组件,支持播放控制、进度条调节、音量控制、播放列表等功能 | 6 | * @Description: 音频播放器组件,支持播放控制、进度条调节、音量控制、播放列表等功能 |
| 7 | --> | 7 | --> |
| ... | @@ -12,7 +12,7 @@ | ... | @@ -12,7 +12,7 @@ |
| 12 | <div class="flex flex-col items-center mb-4"> | 12 | <div class="flex flex-col items-center mb-4"> |
| 13 | <!-- 歌曲封面 --> | 13 | <!-- 歌曲封面 --> |
| 14 | <div class="w-24 h-24 rounded-lg overflow-hidden mb-2"> | 14 | <div class="w-24 h-24 rounded-lg overflow-hidden mb-2"> |
| 15 | - <img :src="currentSong?.cover" alt="封面" class="w-full h-full object-cover"> | 15 | + <img :src="currentSong?.cover ? currentSong?.cover : 'https://cdn.ipadbiz.cn/mlaj/images/audio_d_cover.jpg'" alt="封面" class="w-full h-full object-cover"> |
| 16 | </div> | 16 | </div> |
| 17 | 17 | ||
| 18 | <!-- 歌曲信息 --> | 18 | <!-- 歌曲信息 --> |
| ... | @@ -105,7 +105,7 @@ | ... | @@ -105,7 +105,7 @@ |
| 105 | > | 105 | > |
| 106 | <div class="absolute top-0 left-0 right-0 h-[1px] bg-gray-200"></div> | 106 | <div class="absolute top-0 left-0 right-0 h-[1px] bg-gray-200"></div> |
| 107 | <div class="w-16 h-16 rounded-lg overflow-hidden mr-4 flex-shrink-0"> | 107 | <div class="w-16 h-16 rounded-lg overflow-hidden mr-4 flex-shrink-0"> |
| 108 | - <img :src="song?.cover" alt="封面" class="w-full h-full object-cover"> | 108 | + <img :src="song?.cover ? song?.cover : 'https://cdn.ipadbiz.cn/mlaj/images/audio_d_cover.jpg'" alt="封面" class="w-full h-full object-cover"> |
| 109 | </div> | 109 | </div> |
| 110 | <div class="flex-1"> | 110 | <div class="flex-1"> |
| 111 | <div class="font-medium">{{ song?.title }}</div> | 111 | <div class="font-medium">{{ song?.title }}</div> |
| ... | @@ -177,6 +177,9 @@ const loadAudio = async () => { | ... | @@ -177,6 +177,9 @@ const loadAudio = async () => { |
| 177 | } | 177 | } |
| 178 | } | 178 | } |
| 179 | 179 | ||
| 180 | +// 定义组件事件 | ||
| 181 | +const emit = defineEmits(['play', 'pause']) | ||
| 182 | + | ||
| 180 | // 播放控制:切换播放/暂停状态 | 183 | // 播放控制:切换播放/暂停状态 |
| 181 | const togglePlay = async () => { | 184 | const togglePlay = async () => { |
| 182 | if (isLoading.value) return | 185 | if (isLoading.value) return |
| ... | @@ -186,8 +189,10 @@ const togglePlay = async () => { | ... | @@ -186,8 +189,10 @@ const togglePlay = async () => { |
| 186 | } | 189 | } |
| 187 | if (isPlaying.value) { | 190 | if (isPlaying.value) { |
| 188 | await audio.value?.pause() | 191 | await audio.value?.pause() |
| 192 | + emit('pause', audio.value) | ||
| 189 | } else { | 193 | } else { |
| 190 | await audio.value?.play() | 194 | await audio.value?.play() |
| 195 | + emit('play', audio.value) | ||
| 191 | } | 196 | } |
| 192 | isPlaying.value = !isPlaying.value | 197 | isPlaying.value = !isPlaying.value |
| 193 | } catch (error) { | 198 | } catch (error) { |
| ... | @@ -195,6 +200,19 @@ const togglePlay = async () => { | ... | @@ -195,6 +200,19 @@ const togglePlay = async () => { |
| 195 | } | 200 | } |
| 196 | } | 201 | } |
| 197 | 202 | ||
| 203 | +// 暴露给父组件的方法 | ||
| 204 | +defineExpose({ | ||
| 205 | + togglePlay, | ||
| 206 | + pause: () => { | ||
| 207 | + if (isPlaying.value && audio.value) { | ||
| 208 | + audio.value.pause(); | ||
| 209 | + isPlaying.value = false; | ||
| 210 | + emit('pause', audio.value); | ||
| 211 | + } | ||
| 212 | + }, | ||
| 213 | + isPlaying: () => isPlaying.value | ||
| 214 | +}) | ||
| 215 | + | ||
| 198 | // 进度更新 | 216 | // 进度更新 |
| 199 | const updateProgress = () => { | 217 | const updateProgress = () => { |
| 200 | if (!audio.value) return | 218 | if (!audio.value) return |
| ... | @@ -223,6 +241,8 @@ const prevSong = async () => { | ... | @@ -223,6 +241,8 @@ const prevSong = async () => { |
| 223 | const normalizedVolume = Math.pow(volume.value / 100, 2) | 241 | const normalizedVolume = Math.pow(volume.value / 100, 2) |
| 224 | audio.value.volume = normalizedVolume | 242 | audio.value.volume = normalizedVolume |
| 225 | isPlaying.value = true | 243 | isPlaying.value = true |
| 244 | + // 发射播放事件 | ||
| 245 | + emit('play', audio.value) | ||
| 226 | } | 246 | } |
| 227 | } | 247 | } |
| 228 | 248 | ||
| ... | @@ -241,6 +261,8 @@ const nextSong = async () => { | ... | @@ -241,6 +261,8 @@ const nextSong = async () => { |
| 241 | const normalizedVolume = Math.pow(volume.value / 100, 2) | 261 | const normalizedVolume = Math.pow(volume.value / 100, 2) |
| 242 | audio.value.volume = normalizedVolume | 262 | audio.value.volume = normalizedVolume |
| 243 | isPlaying.value = true | 263 | isPlaying.value = true |
| 264 | + // 发射播放事件 | ||
| 265 | + emit('play', audio.value) | ||
| 244 | } | 266 | } |
| 245 | } | 267 | } |
| 246 | 268 | ||
| ... | @@ -312,6 +334,8 @@ const selectSong = async (index) => { | ... | @@ -312,6 +334,8 @@ const selectSong = async (index) => { |
| 312 | if (audio.value) { | 334 | if (audio.value) { |
| 313 | await audio.value.play() | 335 | await audio.value.play() |
| 314 | isPlaying.value = true | 336 | isPlaying.value = true |
| 337 | + // 发射播放事件 | ||
| 338 | + emit('play', audio.value) | ||
| 315 | // 关闭播放列表 | 339 | // 关闭播放列表 |
| 316 | isPlaylistVisible.value = false | 340 | isPlaylistVisible.value = false |
| 317 | // 滚动到当前播放的音频 | 341 | // 滚动到当前播放的音频 | ... | ... |
| ... | @@ -119,12 +119,12 @@ onBeforeUnmount(() => { | ... | @@ -119,12 +119,12 @@ onBeforeUnmount(() => { |
| 119 | defineExpose({ | 119 | defineExpose({ |
| 120 | pause() { | 120 | pause() { |
| 121 | if (player.value) { | 121 | if (player.value) { |
| 122 | - player.value.pause(); | 122 | + player.value?.pause(); |
| 123 | } | 123 | } |
| 124 | }, | 124 | }, |
| 125 | play() { | 125 | play() { |
| 126 | if (player.value) { | 126 | if (player.value) { |
| 127 | - player.value.play(); | 127 | + player.value?.play(); |
| 128 | } | 128 | } |
| 129 | }, | 129 | }, |
| 130 | }); | 130 | }); | ... | ... |
This diff is collapsed. Click to expand it.
-
Please register or login to post a comment