You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							289 lines
						
					
					
						
							7.6 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							289 lines
						
					
					
						
							7.6 KiB
						
					
					
				| <template> | |
|   <view class="audio-control" :style="{top:top}" @click.stop="toggleAudio"> | |
| 	  <image v-if="isAudioPlaying" :src="showImg('/uploads/20250904/c7ddc330d25a0916885a31f1d28f6665.png')" mode="" style="width: 80rpx;height: 80rpx;"></image> | |
| 	  <image v-else :src="showImg('/uploads/20250904/057669bd710740650db1cafd414c08c9.png')" mode="" style="width: 80rpx;height: 80rpx;"></image> | |
|   </view> | |
| </template> | |
| 
 | |
| <script> | |
| export default { | |
|   name: 'AudioControl', | |
|   inheritAttrs: false, | |
|   props: { | |
|     // 音频文件路径 | |
|     audioSrc: { | |
|       type: String, | |
|       required: true | |
|     }, | |
| 	top:{ | |
| 		type:String, | |
| 		default:'180rpx' | |
| 	}, | |
|     // 是否显示组件 | |
|     visible: { | |
|       type: Boolean, | |
|       default: true | |
|     } | |
|   }, | |
|   data() { | |
|     return { | |
|       isAudioPlaying: false, | |
|       audioContext: null, | |
|       backgroundMusicWasPlaying: false, // 记录背景音乐之前的状态 | |
|       audioInstanceId: null // 音频实例标识 | |
|     } | |
|   }, | |
|   mounted() { | |
|     this.initAudio(); | |
|      | |
|     // 监听背景音乐切换事件 | |
|     uni.$on('backgroundMusicToggle', this.handleBackgroundMusicToggle); | |
|      | |
|     // 页面加载时检查是否有全局音频在播放 | |
|     this.checkGlobalAudioState(); | |
|   }, | |
|   beforeUnmount() { | |
|     this.destroyAudio(); | |
|      | |
|     // 移除事件监听 | |
|     uni.$off('backgroundMusicToggle', this.handleBackgroundMusicToggle); | |
|   }, | |
|   methods: { | |
|     initAudio() { | |
|       try { | |
|         // 检查是否已有全局音频实例 | |
|         const app = getApp(); | |
|         if (app && app.globalData && app.globalData.currentAudio) { | |
|           // 如果有全局音频且URL匹配,则复用 | |
|           if (app.globalData.currentAudio.src === this.audioSrc) { | |
|             this.audioContext = app.globalData.currentAudio; | |
|             this.isAudioPlaying = !this.audioContext.paused; | |
|             this.setupAudioEvents(); | |
|             return; | |
|           } else { | |
|             // 如果URL不匹配,停止之前的音频 | |
|             app.globalData.currentAudio.stop(); | |
|             app.globalData.currentAudio.destroy(); | |
|           } | |
|         } | |
|          | |
|         // 创建新的音频上下文 | |
|         this.audioContext = uni.createInnerAudioContext(); | |
|         this.audioContext.src = this.audioSrc; | |
|          | |
|         // 保存到全局 | |
|         if (app && app.globalData) { | |
|           app.globalData.currentAudio = this.audioContext; | |
|         } | |
|          | |
|         this.setupAudioEvents(); | |
|          | |
|       } catch (error) { | |
|         console.error('初始化音频失败:', error); | |
|       } | |
|     }, | |
|      | |
|     setupAudioEvents() { | |
|       if (!this.audioContext) return; | |
|        | |
|       // 监听音频事件 | |
|       this.audioContext.onPlay(() => { | |
|         this.isAudioPlaying = true; | |
|         console.log('音频开始播放'); | |
|       }); | |
|        | |
|       this.audioContext.onPause(() => { | |
|         this.isAudioPlaying = false; | |
|         console.log('音频暂停'); | |
|       }); | |
|        | |
|       this.audioContext.onStop(() => { | |
|         this.isAudioPlaying = false; | |
|         console.log('音频停止'); | |
|       }); | |
|        | |
|       this.audioContext.onEnded(() => { | |
|         this.isAudioPlaying = false; | |
|         // 音频播放结束后恢复背景音乐 | |
|         this.restoreBackgroundMusic(); | |
|         console.log('音频播放结束'); | |
|       }); | |
|        | |
|       this.audioContext.onError((err) => { | |
|         console.error('音频播放错误:', err); | |
|         this.isAudioPlaying = false; | |
|         // 发生错误时也恢复背景音乐 | |
|         this.restoreBackgroundMusic(); | |
|       }); | |
|     }, | |
|      | |
|     checkGlobalAudioState() { | |
|       try { | |
|         const app = getApp(); | |
|         if (app && app.globalData && app.globalData.currentAudio) { | |
|           const globalAudio = app.globalData.currentAudio; | |
|           // 如果全局音频的URL与当前组件的URL匹配 | |
|           if (globalAudio.src === this.audioSrc) { | |
|             this.isAudioPlaying = !globalAudio.paused; | |
|             console.log('同步全局音频状态:', this.isAudioPlaying); | |
|           } | |
|         } | |
|       } catch (error) { | |
|         console.error('检查全局音频状态失败:', error); | |
|       } | |
|     }, | |
|      | |
|     toggleAudio() { | |
|       if (!this.audioContext) { | |
|         console.error('音频上下文未初始化'); | |
|         return; | |
|       } | |
|        | |
|       if (this.isAudioPlaying) { | |
|         // 暂停音频,恢复背景音乐 | |
|         this.pauseAudio(); | |
|       } else { | |
|         // 播放音频,暂停背景音乐 | |
|         this.playAudio(); | |
|       } | |
|     }, | |
|      | |
|     playAudio() { | |
|       try { | |
|         // 记录背景音乐当前状态并暂停 | |
|         this.pauseBackgroundMusic(); | |
|          | |
|         // 播放音频 | |
|         this.audioContext.play(); | |
|          | |
|         // 发送音频播放事件 | |
|         uni.$emit('audioPlaying', true); | |
|       } catch (error) { | |
|         console.error('播放音频失败:', error); | |
|       } | |
|     }, | |
|      | |
|     pauseAudio() { | |
|       try { | |
|         // 暂停音频 | |
|         this.audioContext.pause(); | |
|          | |
|         // 恢复背景音乐 | |
|         this.restoreBackgroundMusic(); | |
|          | |
|         // 发送音频停止事件 | |
|         uni.$emit('audioPlaying', false); | |
|       } catch (error) { | |
|         console.error('暂停音频失败:', error); | |
|       } | |
|     }, | |
|      | |
|     pauseBackgroundMusic() { | |
|       try { | |
|         const app = getApp(); | |
|         if (app && app.globalData && app.globalData.bgMusic) { | |
|           // 记录背景音乐当前状态 | |
|           this.backgroundMusicWasPlaying = app.globalData.isMusicPlaying; | |
|            | |
|           // 如果背景音乐正在播放,则暂停 | |
|           if (this.backgroundMusicWasPlaying) { | |
|             app.globalData.bgMusic.pause(); | |
|             console.log('背景音乐已暂停'); | |
|           } | |
|         } | |
|       } catch (error) { | |
|         console.error('暂停背景音乐失败:', error); | |
|       } | |
|     }, | |
|      | |
|     restoreBackgroundMusic() { | |
|       try { | |
|         const app = getApp(); | |
|         if (app && app.globalData && app.globalData.bgMusic && this.backgroundMusicWasPlaying) { | |
|           // 恢复背景音乐播放 | |
|           app.globalData.bgMusic.play(); | |
|           console.log('背景音乐已恢复'); | |
|         } | |
|       } catch (error) { | |
|         console.error('恢复背景音乐失败:', error); | |
|       } | |
|     }, | |
|      | |
|     destroyAudio() { | |
|       // 注意:不销毁全局音频实例,只是断开当前组件的连接 | |
|       console.log('AudioControl组件销毁,但保持全局音频实例'); | |
|       // 清空当前组件的引用,但不销毁全局音频 | |
|       this.audioContext = null; | |
|     }, | |
|      | |
|     // 处理背景音乐切换事件 | |
|     handleBackgroundMusicToggle() { | |
|       // 如果音频正在播放,则暂停音频(但不恢复背景音乐) | |
|       if (this.isAudioPlaying) { | |
|         try { | |
|           // 只暂停音频,不恢复背景音乐 | |
|           this.audioContext.pause(); | |
|            | |
|           // 发送音频停止事件 | |
|           uni.$emit('audioPlaying', false); | |
|            | |
|           console.log('背景音乐切换时暂停音频(不恢复背景音乐)'); | |
|         } catch (error) { | |
|           console.error('暂停音频失败:', error); | |
|         } | |
|       } | |
|     } | |
|   }, | |
|   watch: { | |
|     // 监听音频源变化 | |
|     audioSrc: { | |
|       handler(newSrc) { | |
|         if (this.audioContext && newSrc) { | |
|           this.audioContext.src = newSrc; | |
|         } | |
|       }, | |
|       immediate: true | |
|     } | |
|   } | |
| } | |
| </script> | |
| 
 | |
| <style lang="scss" scoped> | |
| .audio-control { | |
|   position: absolute; | |
|   top: 180rpx; | |
|   right: 30rpx; | |
|   width: 80rpx; | |
|   height: 80rpx; | |
|   border-radius: 50%; | |
|   // background-color: rgba(0, 0, 0, 0.5); | |
|   display: flex; | |
|   align-items: center; | |
|   justify-content: center; | |
|   z-index: 998; | |
|   transition: all 0.3s ease; | |
|    | |
|   &:active { | |
|     transform: scale(0.95); | |
|   } | |
| } | |
| 
 | |
| .audio-icon { | |
|   font-size: 36rpx; | |
|   color: #fff; | |
|   transition: all 0.3s ease; | |
| } | |
| 
 | |
| .playing { | |
|   animation: pulse 1.5s ease-in-out infinite; | |
| } | |
| 
 | |
| @keyframes pulse { | |
|   0%, 100% { | |
|     transform: scale(1); | |
|   } | |
|   50% { | |
|     transform: scale(1.1); | |
|   } | |
| } | |
| </style> |