findme-miniprogram-frontend/components/voice-message/voice-message.js

162 lines
3.7 KiB
JavaScript
Raw Normal View History

2025-12-27 17:16:03 +08:00
Component({
properties: {
// 语音消息数据
voiceData: {
type: Object,
value: {},
observer: 'onVoiceDataChange'
},
// 是否为自己发送的消息
isSelf: {
type: Boolean,
value: false
},
// 消息ID
messageId: {
type: String,
value: ''
}
},
data: {
// 播放状态
isPlaying: false,
// 波形数据
waveformData: [],
// 语音信息
voiceUrl: '',
voiceDuration: 0
},
lifetimes: {
attached() {
this.initComponent();
},
detached() {
this.cleanup();
}
},
methods: {
// 初始化组件
initComponent() {
// 生成波形数据
this.generateWaveform();
// 获取全局音频上下文
const app = getApp();
this.audioContext = app.globalData.audioContext || wx.createInnerAudioContext();
// 注册音频事件
this.setupAudioEvents();
},
// 语音数据变化处理
onVoiceDataChange(newData, oldData) {
if (!newData || JSON.stringify(newData) === JSON.stringify(oldData)) {
return;
}
this.setData({
voiceUrl: newData.url || '',
voiceDuration: newData.duration || 0
});
// 重新生成波形
this.generateWaveform();
},
// 设置音频事件监听
setupAudioEvents() {
if (!this.audioContext) return;
this.audioContext.onPlay(() => {
if (this.isCurrentAudio()) {
this.setData({ isPlaying: true });
}
});
this.audioContext.onPause(() => {
if (this.isCurrentAudio()) {
this.setData({ isPlaying: false });
}
});
this.audioContext.onEnded(() => {
if (this.isCurrentAudio()) {
this.setData({ isPlaying: false });
}
});
this.audioContext.onError((err) => {
console.error('语音播放错误:', err);
if (this.isCurrentAudio()) {
this.setData({ isPlaying: false });
wx.showToast({ title: '播放失败', icon: 'none' });
}
});
},
// 检查是否为当前音频
isCurrentAudio() {
return this.audioContext && this.audioContext.src === this.data.voiceUrl;
},
// 切换播放状态
togglePlay() {
if (!this.data.voiceUrl) {
wx.showToast({ title: '语音地址无效', icon: 'none' });
return;
}
try {
if (this.data.isPlaying) {
this.audioContext.pause();
} else {
// 停止其他正在播放的音频
if (this.audioContext.src !== this.data.voiceUrl) {
this.audioContext.src = this.data.voiceUrl;
}
this.audioContext.play();
}
} catch (error) {
console.error('播放语音失败:', error);
wx.showToast({ title: '播放失败', icon: 'none' });
}
},
// 生成波形数据
generateWaveform() {
const duration = this.data.voiceDuration || 1000;
const barCount = Math.min(Math.max(Math.floor(duration / 200), 8), 30); // 8-30个波形条
const waveformData = [];
for (let i = 0; i < barCount; i++) {
// 生成随机高度,模拟真实波形
const height = Math.random() * 60 + 20; // 20-80%的高度
waveformData.push(height);
}
this.setData({ waveformData });
},
// 清理资源
cleanup() {
// 如果当前正在播放,停止播放
if (this.data.isPlaying && this.audioContext) {
try {
this.audioContext.stop();
} catch (e) {
// 忽略停止错误
}
}
}
}
});