首先找规律,根据我的发现,有以下结论,假定我有五首歌:
let musics = [A, B, C, D, E, F]
// 如果刚进来的时候点击 B 这首歌播放,接下来点击下一曲是随机的,但是不会重复,说明播放一首,随机中就不再含有这首歌
// 也就是 B [A, C, D, E, F] 这几首歌中随机播放一首,此时如果是 F
// 那么这一次就是从 B F [A, C, D, E] 中随机一首
// 如果第一轮结束了,第二轮的时候也是随机,我测试到上一曲和下一曲相同的情况,我实现的时候不会有这种情况
// 基于这种规律可以有两种(想到的)方式:
// 1) 保持点击的第一首歌曲不变,其余的先随机组成新数组,然后根据下标逐步执行即可
// 2) 没点击一次都从没有播放过的原始列表中随机一首
我使用这一种方式,首先定义类:
class RandomPlay {
playList = [];
currentPlayIndex = -1;
size = 0;
constructor(selectedMusic, allMusics) {
this.playList.push(...this.randomMusics(selectedMusic, allMusics));
this.size = allMusics?.length || 0;
this.currentPlayIndex = this.size === 0 ? -1 : 0;
}
play = () => {
// 播放当前的歌曲,如果数据出现错误就抛出
if (this.currentPlayIndex < 0) {
throw new Error("播放错误")
}
return this.playList[this.currentPlayIndex];
};
// 得到随机列表,第一个参数是照顾用户手动点击的那一首
randomMusics = (selectedMusic, musics = [], isFount = false) => {
if (!Array.isArray(musics)) {
return [];
}
const len = musics.length - 1;
// 过滤掉传进来的那一首歌曲
const tempMusics = musics.filter((music) => music !== selectedMusic);
for (let i = 0; i < len; i++) {
// 我随机的方式就是随机交换
const index = Math.floor(Math.random() * (len - i) + i);
let tempMusic = tempMusics[i];
tempMusics[i] = tempMusics[index];
tempMusics[index] = tempMusic;
}
// 根据这个字段判断传进来的是传入到头部还是尾部
if (isFount) {
tempMusics.push(selectedMusic)
} else {
tempMusics.unshift(selectedMusic);
}
return tempMusics;
};
// 下一曲,不会出现连续两次都播放同一歌曲,跟官方不同
nextMusic = () => {
this.currentPlayIndex += 1;
const len = this.playList.length;
// 如果播放的下标于播放数组相同了说明已经到头了
if (this.currentPlayIndex === len) {
// 首先从最后一首前面的歌曲中随机找一首放在下一个位置,这样下一首一定不会出现上一首
const tempIndex = Math.random() * (this.size - 1) + (len - this.size)
const index = Math.floor(tempIndex);
// 把新生成的加进去,这样是为了用户点击上一曲
this.playList.push(...this.randomMusics(this.playList[index], this.playList.slice(len - this.size)));
}
return this.playList[this.currentPlayIndex];
};
// 上一曲,这个地方我跟规律不同,下面会修改
lastMusic = () => {
// 如果是 -1 说明历史播放列表中没有歌曲了
this.currentPlayIndex -= 1;
if (this.currentPlayIndex === -1) {
// 随机歌曲数组,放于播放列表的头部
const tempIndex = Math.random() * (this.size - 2) + 1
const index = Math.floor(tempIndex);
this.playList.unshift(...this.randomMusics(this.playList[index],this.playList.slice(0, this.size), true));
this.currentPlayIndex = this.size - 1;
}
return this.playList[this.currentPlayIndex]
};
}