165 lines
4.8 KiB
JavaScript
Raw Normal View History

2025-06-06 15:17:30 +08:00
const utils = require("../../../utils/utils");
Page({
data: {
2026-08-04 09:59:35 +08:00
title: "音乐",
data: {},
playlist: [],
currentIndex: 0,
value: "00:00",
duration: "00:00",
percent: 0,
isPlay: false,
isSingleLoop: false,
isShow: false,
isClosing: false
2025-06-06 15:17:30 +08:00
},
onLoad(options) {
2026-08-04 09:59:35 +08:00
let current = {};
try {
current = JSON.parse(decodeURIComponent(options.data || "{}"));
} catch (error) {
console.error("资源参数解析失败", error);
}
2025-06-06 15:17:30 +08:00
this.setData({
2026-08-04 09:59:35 +08:00
data: current,
playlist: current.resourceUrl ? [current] : [],
title: current.id == 1 ? "口令" : "音乐"
});
this.createAudioContext();
if (current.resourceUrl) {
this.loadTrack(current, false);
}
2025-06-06 15:17:30 +08:00
2026-08-04 09:59:35 +08:00
const eventChannel = this.getOpenerEventChannel && this.getOpenerEventChannel();
if (eventChannel && eventChannel.on) {
eventChannel.on("setPlaylist", ({ playlist = [], currentIndex = 0 }) => {
if (!playlist.length) return;
const safeIndex = Math.min(Math.max(Number(currentIndex) || 0, 0), playlist.length - 1);
this.setData({ playlist, currentIndex: safeIndex, data: playlist[safeIndex] });
});
}
2025-06-06 15:17:30 +08:00
},
2026-08-04 09:59:35 +08:00
createAudioContext() {
this.audioCtx = wx.createInnerAudioContext();
this.audioCtx.obeyMuteSwitch = false;
this.audioCtx.onCanplay(() => this.updateProgress());
this.audioCtx.onTimeUpdate(() => this.updateProgress());
this.audioCtx.onPlay(() => this.setData({ isPlay: true }));
this.audioCtx.onPause(() => this.setData({ isPlay: false }));
this.audioCtx.onStop(() => this.setData({ isPlay: false }));
this.audioCtx.onEnded(() => {
if (!this.data.isSingleLoop) this.changeTrack(1, true);
});
this.audioCtx.onError((error) => {
console.error("音频播放失败", error);
this.setData({ isPlay: false });
wx.showToast({ title: "音频加载失败,请稍后重试", icon: "none" });
});
2025-06-06 15:17:30 +08:00
},
2026-08-04 09:59:35 +08:00
loadTrack(track, autoplay = true) {
if (!track || !track.resourceUrl || !this.audioCtx) return;
this.audioCtx.stop();
this.audioCtx.loop = this.data.isSingleLoop;
this.audioCtx.src = track.resourceUrl;
2025-06-06 15:17:30 +08:00
this.setData({
2026-08-04 09:59:35 +08:00
data: track,
value: "00:00",
duration: "00:00",
percent: 0,
isPlay: autoplay
});
if (autoplay) this.audioCtx.play();
2025-06-06 15:17:30 +08:00
},
2026-08-04 09:59:35 +08:00
updateProgress() {
if (!this.audioCtx) return;
const currentTime = Number(this.audioCtx.currentTime) || 0;
const duration = Number(this.audioCtx.duration) || 0;
2025-06-06 15:17:30 +08:00
this.setData({
2026-08-04 09:59:35 +08:00
value: utils.formatTimeStr(currentTime),
duration: utils.formatTimeStr(duration),
percent: duration ? Math.min((currentTime / duration) * 100, 100) : 0
});
2025-06-06 15:17:30 +08:00
},
2026-08-04 09:59:35 +08:00
btnCilck() {
if (!this.audioCtx || !this.data.data.resourceUrl) return;
this.data.isPlay ? this.audioCtx.pause() : this.audioCtx.play();
2025-06-06 15:17:30 +08:00
},
2026-08-04 09:59:35 +08:00
playPrevious() {
this.changeTrack(-1, true);
2025-06-06 15:17:30 +08:00
},
2026-08-04 09:59:35 +08:00
playNext() {
this.changeTrack(1, true);
},
2025-06-06 15:17:30 +08:00
2026-08-04 09:59:35 +08:00
changeTrack(step, autoplay) {
const { playlist, currentIndex } = this.data;
if (!playlist.length) return;
const nextIndex = (currentIndex + step + playlist.length) % playlist.length;
this.setData({ currentIndex: nextIndex }, () => this.loadTrack(playlist[nextIndex], autoplay));
2025-06-06 15:17:30 +08:00
},
2026-08-04 09:59:35 +08:00
selectTrack(e) {
const index = Number(e.currentTarget.dataset.index);
if (!Number.isInteger(index) || !this.data.playlist[index]) return;
this.setData({ currentIndex: index }, () => {
this.loadTrack(this.data.playlist[index], true);
this.hideList();
});
2025-06-06 15:17:30 +08:00
},
2026-08-04 09:59:35 +08:00
toggleLoop() {
const isSingleLoop = !this.data.isSingleLoop;
if (this.audioCtx) this.audioCtx.loop = isSingleLoop;
this.setData({ isSingleLoop });
wx.showToast({ title: isSingleLoop ? "单曲循环" : "列表循环", icon: "none" });
},
2025-06-06 15:17:30 +08:00
2026-08-04 09:59:35 +08:00
seekAudio(e) {
if (!this.audioCtx || !this.audioCtx.duration) return;
wx.createSelectorQuery().in(this).select("#audio-progress").boundingClientRect((rect) => {
if (!rect || !rect.width) return;
const ratio = Math.min(Math.max((e.detail.x - rect.left) / rect.width, 0), 1);
this.audioCtx.seek(this.audioCtx.duration * ratio);
}).exec();
2025-06-06 15:17:30 +08:00
},
2026-08-04 09:59:35 +08:00
showList() {
if (this.closeTimer) {
clearTimeout(this.closeTimer);
this.closeTimer = null;
}
this.setData({ isShow: true, isClosing: false });
},
2025-06-06 15:17:30 +08:00
2026-08-04 09:59:35 +08:00
hideList() {
if (!this.data.isShow || this.data.isClosing) return;
this.setData({ isClosing: true });
this.closeTimer = setTimeout(() => {
this.setData({ isShow: false, isClosing: false });
this.closeTimer = null;
}, 240);
2025-06-06 15:17:30 +08:00
},
2026-08-04 09:59:35 +08:00
preventClose() {},
2025-06-06 15:17:30 +08:00
2026-08-04 09:59:35 +08:00
onUnload() {
if (this.closeTimer) clearTimeout(this.closeTimer);
if (this.audioCtx) {
this.audioCtx.stop();
if (this.audioCtx.destroy) this.audioCtx.destroy();
this.audioCtx = null;
}
2025-06-06 15:17:30 +08:00
}
2026-08-04 09:59:35 +08:00
});