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>
|