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.
225 lines
5.6 KiB
225 lines
5.6 KiB
2 months ago
|
# 跨页面音频控制解决方案
|
||
|
|
||
|
## 进一步优化:解决跨页面状态同步问题
|
||
|
|
||
|
### 问题描述
|
||
|
在跨页面场景下,当音频正在播放时跳转到新页面,新页面的MusicControl组件不知道有音频在播放,点击背景音乐按钮时会直接播放背景音乐,导致音频和背景音乐同时播放。
|
||
|
|
||
|
### 解决方案
|
||
|
|
||
|
#### 1. MusicControl组件增强检测
|
||
|
```javascript
|
||
|
// 在mounted生命周期中添加全局音频状态检测
|
||
|
mounted() {
|
||
|
this.syncMusicState();
|
||
|
this.checkGlobalAudioState(); // 新增:检查全局音频状态
|
||
|
|
||
|
// 定时器也要检查全局音频状态
|
||
|
this.timer = setInterval(() => {
|
||
|
this.syncMusicState();
|
||
|
this.checkGlobalAudioState();
|
||
|
}, 1000);
|
||
|
}
|
||
|
|
||
|
// 新增方法:检查全局音频状态
|
||
|
checkGlobalAudioState() {
|
||
|
const app = getApp();
|
||
|
if (app && app.globalData && app.globalData.currentAudio) {
|
||
|
const globalAudio = app.globalData.currentAudio;
|
||
|
this.isAudioPlaying = !globalAudio.paused;
|
||
|
} else {
|
||
|
this.isAudioPlaying = false;
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
#### 2. 全局音频管理工具优化
|
||
|
```javascript
|
||
|
// 在音频状态变化时发送全局事件
|
||
|
pauseCurrentAudio() {
|
||
|
const audio = this.getCurrentAudio();
|
||
|
if (audio && !audio.paused) {
|
||
|
audio.pause();
|
||
|
this.notifyAudioStateChange(false); // 通知状态变化
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// 新增:通知音频状态变化
|
||
|
notifyAudioStateChange(isPlaying) {
|
||
|
if (typeof uni !== 'undefined') {
|
||
|
uni.$emit('audioPlaying', isPlaying);
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
### 修复后的交互流程
|
||
|
```mermaid
|
||
|
graph TD
|
||
|
A[跨页面跳转] --> B[MusicControl组件加载]
|
||
|
B --> C[检查全局音频状态]
|
||
|
C --> D{有音频在播放?}
|
||
|
D -->|是| E[设置isAudioPlaying=true]
|
||
|
D -->|否| F[设置isAudioPlaying=false]
|
||
|
E --> G[点击背景音乐按钮]
|
||
|
F --> G
|
||
|
G --> H{检查isAudioPlaying}
|
||
|
H -->|有音频| I[先暂停音频再播放背景音乐]
|
||
|
H -->|无音频| J[直接播放背景音乐]
|
||
|
```
|
||
|
|
||
|
## 问题描述
|
||
|
|
||
|
AudioControl组件在页面跳转时会出现以下问题:
|
||
|
1. 组件状态重置,图标显示不正确
|
||
|
2. 音频实例丢失连接,但音频可能仍在播放
|
||
|
3. 无法在其他页面控制正在播放的音频
|
||
|
|
||
|
## 解决方案
|
||
|
|
||
|
### 1. 全局音频实例管理
|
||
|
|
||
|
在`App.vue`的`globalData`中添加`currentAudio`属性,用于保存当前的音频实例:
|
||
|
|
||
|
```javascript
|
||
|
globalData: {
|
||
|
// ... 其他属性
|
||
|
currentAudio: null // 全局音频实例
|
||
|
}
|
||
|
```
|
||
|
|
||
|
### 2. AudioControl组件优化
|
||
|
|
||
|
#### 状态同步机制
|
||
|
- 组件挂载时检查全局音频状态
|
||
|
- 复用已存在的音频实例(如果URL匹配)
|
||
|
- 组件销毁时不销毁全局音频实例
|
||
|
|
||
|
#### 核心方法改进
|
||
|
```javascript
|
||
|
// 检查全局音频状态
|
||
|
checkGlobalAudioState() {
|
||
|
const app = getApp();
|
||
|
if (app && app.globalData && app.globalData.currentAudio) {
|
||
|
const globalAudio = app.globalData.currentAudio;
|
||
|
if (globalAudio.src === this.audioSrc) {
|
||
|
this.isAudioPlaying = !globalAudio.paused;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 初始化音频时复用全局实例
|
||
|
initAudio() {
|
||
|
const app = getApp();
|
||
|
if (app && app.globalData && app.globalData.currentAudio) {
|
||
|
if (app.globalData.currentAudio.src === this.audioSrc) {
|
||
|
// 复用现有实例
|
||
|
this.audioContext = app.globalData.currentAudio;
|
||
|
this.isAudioPlaying = !this.audioContext.paused;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
// 创建新实例...
|
||
|
}
|
||
|
```
|
||
|
|
||
|
### 3. 全局音频管理工具
|
||
|
|
||
|
创建了`utils/globalAudioManager.js`工具类,提供统一的音频控制接口:
|
||
|
|
||
|
```javascript
|
||
|
// 在任何页面或组件中使用
|
||
|
uni.$globalAudio.pauseCurrentAudio(); // 暂停当前音频
|
||
|
uni.$globalAudio.playCurrentAudio(); // 播放当前音频
|
||
|
uni.$globalAudio.isAudioPlaying(); // 检查播放状态
|
||
|
uni.$globalAudio.getCurrentAudioSrc(); // 获取当前音频源
|
||
|
```
|
||
|
|
||
|
## 使用示例
|
||
|
|
||
|
### 在页面中控制音频
|
||
|
|
||
|
```vue
|
||
|
<template>
|
||
|
<view>
|
||
|
<!-- 音频控制组件 -->
|
||
|
<AudioControl :audioSrc="audioUrl" />
|
||
|
|
||
|
<!-- 手动控制按钮 -->
|
||
|
<button @click="toggleAudio">切换音频</button>
|
||
|
<button @click="stopAudio">停止音频</button>
|
||
|
</view>
|
||
|
</template>
|
||
|
|
||
|
<script>
|
||
|
import AudioControl from '@/components/AudioControl.vue';
|
||
|
|
||
|
export default {
|
||
|
components: { AudioControl },
|
||
|
data() {
|
||
|
return {
|
||
|
audioUrl: this.showImg('/uploads/audio/chapter1.mp3')
|
||
|
}
|
||
|
},
|
||
|
methods: {
|
||
|
toggleAudio() {
|
||
|
if (uni.$globalAudio.isAudioPlaying()) {
|
||
|
uni.$globalAudio.pauseCurrentAudio();
|
||
|
} else {
|
||
|
uni.$globalAudio.playCurrentAudio();
|
||
|
}
|
||
|
},
|
||
|
|
||
|
stopAudio() {
|
||
|
uni.$globalAudio.stopCurrentAudio();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
</script>
|
||
|
```
|
||
|
|
||
|
### 在其他页面检查音频状态
|
||
|
|
||
|
```javascript
|
||
|
// 在任何页面的onShow生命周期中
|
||
|
onShow() {
|
||
|
// 检查是否有音频在播放
|
||
|
if (uni.$globalAudio.isAudioPlaying()) {
|
||
|
console.log('有音频正在播放:', uni.$globalAudio.getCurrentAudioSrc());
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
## 技术优势
|
||
|
|
||
|
### ✅ **状态持久化**
|
||
|
- 音频实例在页面跳转时不会丢失
|
||
|
- 组件状态能够正确同步全局音频状态
|
||
|
|
||
|
### ✅ **跨页面控制**
|
||
|
- 在任何页面都可以控制当前播放的音频
|
||
|
- 提供统一的音频管理接口
|
||
|
|
||
|
### ✅ **资源优化**
|
||
|
- 避免创建多个音频实例
|
||
|
- 自动清理无用的音频资源
|
||
|
|
||
|
### ✅ **用户体验**
|
||
|
- 页面跳转时音频播放不中断
|
||
|
- 图标状态显示正确
|
||
|
- 音频控制逻辑一致
|
||
|
|
||
|
## 注意事项
|
||
|
|
||
|
1. **页面生命周期**:音频实例与页面生命周期解耦,需要手动管理
|
||
|
2. **内存管理**:确保在应用退出时正确清理音频资源
|
||
|
3. **状态同步**:多个AudioControl组件需要监听相同的全局状态
|
||
|
4. **错误处理**:增强错误处理机制,确保音频异常时的状态恢复
|
||
|
|
||
|
## 兼容性
|
||
|
|
||
|
- ✅ uni-app
|
||
|
- ✅ 小程序环境
|
||
|
- ✅ H5环境
|
||
|
- ✅ APP环境
|