网易云音乐的随机播放

552 阅读2分钟

首先找规律,根据我的发现,有以下结论,假定我有五首歌:

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]
  };
}