Vue の NetEase Cloud Music Player インターフェースを模倣したシンプルな実装プロセス

Vue の NetEase Cloud Music Player インターフェースを模倣したシンプルな実装プロセス

仕事のプロジェクトのニーズにより、曲の再生が必要となり、さまざまな資料を参考にして、NetEase Cloud Musicの再生を模倣したインターフェースを作成し、音楽再生機能を完全に実現しました。

フロントエンドでは、vue コンポーネントとオーディオ タグを使用してプレーヤー インターフェイスを実装し、バックエンドでは NetEase Cloud の API を呼び出して対応する曲情報を取得します。

さっそくコードを見てみましょう

曲再生インターフェース (musicPlay.vue)

<テンプレート>
  <div class="メインページ">
    <audio :src="songInfo.url" id="music" autoplay="自動再生"></audio>
    <div
      クラス="背景フリッター"
      :style="`背景画像: url(${songInfo.cover})`"
    </div>
    <div class="play-mini">
      <div class="プログレスバー" @click="handleProgressClick" ref="トラック">
        <div
          クラス="プログレスボックス"
          :style="{ width: audioProgressPercent }"
        </div>
      </div>
      <div class="songInfo">
        <img class="poster" :src="songInfo.cover" alt="" />
        <!-- 曲名、歌手名-->
        <div class="info">
          <p style="font-weight: 600; color: #fff;">{{ songInfo.name }}</p>
          <p style="font-size: 14px; color: #fff">{{ songInfo.artistsName }}</p>
        </div>
      </div>
      <div class="controls">
        <!-- 前の曲のヒント-->
        <Tooltip content="前の曲" theme="light" :delay="1500">
          <a href="javascript:;">
            <アイコン
              タイプ="md-skip-backward"
              @click="戻る"
              サイズ= "26"
              色 = "白"
            />
          </a>
        </ツールチップ>
        <!-- 再生一時停止 -->
        <Tooltip content="再生 一時停止" theme="light" :delay="1500">
          <画像
            @click="音楽を再生"
            クラス="ステータス"
            v-show="!再生中"
            src="@/assets/play_icon.png"
            代替案=""
          />
          <画像
            クラス="ステータス"
            @click="音楽を再生"
            v-show="再生中"
            src="@/assets/play-02.png"
            代替案=""
          />
        </ツールチップ>
        <!-- 次の曲のヒント -->
        <Tooltip content="次の曲" theme="light" :delay="1500">
          <a href="javascript:;">
            <アイコン
              タイプ="md-skip-forward"
              @click="次へ進む"
              サイズ= "26"
              色 = "白"
            />
          </a>
        </ツールチップ>
      </div>
      <div class="右下">
        <div class="text-div"></div>
        <!-- ボリューム -->
        <a href="javascript:;">
          <アイコン
            :type="ボリュームタイプ"
            サイズ= "26"
            色 = "白"
            @click="音量変更"
          />
        </a>
        <div class="text-div"></div>
        <スライダー
          スタイル="幅: 80px; z-index: 99999"
          @on-input="changeVolum"
          v-model="ボリューム"
        </スライダー>
        <div class="text-div"></div>
        <div class="text-div"></div>
        <div class="text-div"></div>
        <!-- 曲の再生タイプ -->
        <ツールチップ:content="showPlayType" theme="light" :delay="1500">
          <a href="javascript:;">
            <アイコン
              :custom="プレイステータス"
              @click="再生タイプ変更"
              サイズ="26"
              色 = "白"
            />
          </a>
        </ツールチップ>
        <div class="text-div"></div>
        <div class="text-div"></div>
        <div class="プレイリスト">
          <!-- プレイリスト -->
          <ツールチップコンテンツ="リスト" テーマ="ライト" :delay="1500">
            <a href="javascript:;">
              <アイコン
                custom="iconfont icon-bofangqi-xuanji"
                @click="引き出し = true"
                サイズ="36"
                色 = "白"
              />
            </a>
          </ツールチップ>
        </div>
      </div>
    </div>
    <div class="song-cover-lyric">
      <div class="ディスクコンテナ">
        <div class="poster" ref="回転">
          <img :src="songInfo.cover" alt="" />
        </div>
        <div class="song-name">{{ songInfo.name }}</div>
        <div class="song-artistsName">{{ songInfo.artistsName }}</div>
      </div>
      <div class="lyric">
        <mscroll
          ref="歌詞"
          :color="色"
          :colorLight="カラーライト"
          :lineHeight="行の高さ"
          :paddingTop="パディングトップ"
          :fontSize="フォントサイズ"
          :lyricIndex="歌詞インデックス"
          :lyricsList="歌詞情報"
        </mスクロール>
      </div>
    </div>
    <引き出し
      title="プレイリスト"
      配置="左"
      幅="320"
      :closeable="false" です
      v-model="引き出し"
    >
      <div class="リストコンテナ">
        <div
          クラス="songInfo"
          v-for="(item, index) in songList"
          :key="インデックス"
          @click="PlayListMusic(インデックス)"
        >
          <img :src="item.cover" alt="" />
          <div class="info">
            <div class="name">{{ item.name }}</div>
            <div class="歌手">{{ item.アーティスト名 }}</div>
          </div>
        </div>
      </div>
    </引き出し>
  </div>
</テンプレート>
<スクリプト>
「../../publicMethod/publicMethods」から { showMessage } をインポートします。
「./lyricScroll.vue」からMscrollをインポートします。
「../../utils/timeConversion」からcommonJsをインポートします。
「axios」からaxiosをインポートします。
エクスポートデフォルト{
  データ() {
    戻る {
      volumeNum: 80, //保存されたボリューム volumeStatus: true, //ボリュームアイコンの変更 volumeType: "md-volume-up", //ボリュームアイコン playStatus: "iconfont icon-xunhuanbofang", //再生タイプアイコン playing: false,
      引き出し: 偽、
      再生インデックス: 0,
      曲情報: {},
      曲リスト: [],
      音量: 80, // 音量 lyricInfo: [],
      playType: 1, // 再生タイプ: 1-リスト ループ、2-ランダム再生、3-シングル ループshowPlayType: "リスト ループ",
      オーディオ進行状況: 0,
      親指の翻訳X: 0,
      歌詞インデックス: 0,
      color: "#fff", //歌詞のデフォルト色 colorLight: "#40ce8f", //歌詞のハイライト色 fontSize: "16px", //歌詞のフォントサイズ lineHeight: "42", //各段落の高さ paddingTop: "300px", //ハイライトされた歌詞部分を中央に配置};
  },
  作成された() {},
  コンポーネント:
    Mscroll、
  },
  計算: {
    オーディオ進行度パーセント() {
      `${this.audioProgress * 100}%` を返します。
    },
  },
  マウント() {
    const music = document.getElementById("music");
    if (this.$route.query.play) {
      this.ClickPlay();
    } それ以外 {
this.GetSongList();
    }
 
    if (this.playing) {
      // 再生中。クリックすると一時停止します。this.playing = false;
      this.$refs.rotate.style.animationPlayState = "一時停止";
      音楽.一時停止();
    } それ以外 {
      // 一時停止。クリックすると再生されます。this.playing = true;
      this.$refs.rotate.style.animationPlayState = "実行中";
      音楽を再生します。
    }
  },
  メソッド: {
    //音量の変更 volumeChange() {
      if (this.volumeStatus) {
        this.volumeStatus = false;
        this.volumeNum = this.volume;
        this.volume = 0;
        this.volumeType = "md-volume-off";
      } それ以外 {
        this.volumeStatus = true;
        this.volume = this.volumeNum;
        this.volumeType = "md-volume-up";
      }
    },
    //曲の再生タイプが変わる playTypeChange() {
      (this.playType == 1)の場合{
        再生タイプ = 2;
        this.showPlayType = "ランダム再生";
        this.playStatus = "iconfont icon-suijibofang";
        戻る;
      }
      (this.playType == 2)の場合{
        this.playType = 3;
        this.showPlayType = "シングルループ";
        this.playStatus = "iconfont icon-danquxunhuan";
        戻る;
      }
      (this.playType == 3)の場合{
        this.playType = 1;
        this.showPlayType = "リストループ";
        this.playStatus = "iconfont icon-xunhuanbofang";
        戻る;
      }
    },
    クリック再生() {
      このオーディオを初期化します。
      this.getMusicList(this.songInfo.id);
      this.$refs.rotate.style.animationPlayState = "実行中";
      this.playing = true;
      タイムアウトを設定する(() => {
        音楽を再生します。
      }, 100);
    },
    GetSongList() {
      axios.get("/musicController/getMusicList").then(this.GetSongListInfo);
    },
    GetSongListInfo(res) {
      myList を作成します。
      (res.code == "0000"の場合){
        myList = res.data;
      } それ以外 {
        console.log("データが見つかりません");
        myList = [
          {
            アーティスト名:「地主の猫」
            カバー:
              "https://p3.music.126.net/KkrcSwKbRsd8GuaOHILlxA==/109951166077317301.jpg",
            id: 1857630559、
            名前: 「新入生」
            URL: "https://music.163.com/song/media/outer/url?id=1857630559.mp3",
            歌詞:
              : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :
          },
        ];
      }
      this.songList = myList;
      this.songList[0] をコピーします。
      this.getMusicList(this.songInfo.id); //再生中の曲のIDから、再生中の曲のURL歌詞情報を取得します。this.audioInit();
    },
    オーディオ初期化() {
      that = this とする;
      let progressL = this.$refs.track.offsetWidth; // プログレスバーの合計の長さ music.addEventListener("timeupdate", () => {
        // 現在の再生時間 let compareTime = music.currentTime;
        (i = 0 とします; i < that.lyricInfo.length; i++) {
          比較時間 > parseInt(that.lyricInfo[i].time) の場合 {
            定数インデックス = that.lyricInfo[i].index;
            if (i === parseInt(index)) {
              that.lyricIndex = i;
            }
          }
        }
        that.currentTime = commonJs.TimeToString(music.currentTime);
        that.audioProgress = music.currentTime / music.duration;
        that.thumbTranslateX = (that.audioProgress * progressL).toFixed(3);
      });
      music.addEventListener("終了", () => {
        スイッチ(parseInt(that.playType)){
          ケース1: // リストループ that.playIndex =
              that.playIndex + 1 >= that.songList.length
                ? 0
                : that.playIndex + 1;
            壊す;
          ケース 2: // ランダムに再生する that.playIndex = Math.floor(Math.random() * that.songList.length);
            壊す;
          ケース 3: // 単一ループ break;
        }
        that.songInfo = that.songList[that.playIndex];
        this.getMusicList(that.songInfo.id);
        タイムアウトを設定する(() => {
          this.$refs.rotate.style.animationPlayState = "実行中";
          音楽を再生します。
        }, 200);
      });
    },
    //再生と一時停止 playMusic() {
      if (this.playing) {
        // 再生中。クリックすると一時停止します。this.playing = false;
        this.$refs.rotate.style.animationPlayState = "一時停止";
        音楽.一時停止();
      } それ以外 {
        // 一時停止。クリックすると再生されます。this.playing = true;
        this.$refs.rotate.style.animationPlayState = "実行中";
        音楽を再生します。
      }
    },
    プレイリストミュージック(インデックス) {
      this.playIndex = インデックス;
      this.songInfo = this.songList[this.playIndex];
      this.getMusicList(this.songInfo.id);
      this.playing = true;
      this.drawer は false です。
      タイムアウトを設定する(() => {
        this.$refs.rotate.style.animationPlayState = "実行中";
        音楽を再生します。
      }, 200);
    },
    //プログレスバーをクリック handleProgressClick(event) {
      let progressL = this.$refs.track.offsetWidth; // プログレスバーの合計の長さ let clickX = event.offsetX;
      time = (clickX / progressL).toFixed(2) とします。
      this.setProgress(時間);
    },
    setProgress(x) {
      music.currentTime = music.duration * x;
    },
    // 前の曲 skipBack() {
      this.skipFn("スキップバック");
    },
    // 次の曲 skipForward() {
      this.skipFn("前方へスキップ");
    },
    // 上部と下部のヘッダーのカプセル化 skipFn(type) {
      スイッチ(parseInt(this.playType)){
        ケース 2: // ランダムに再生 this.playIndex = Math.floor(Math.random() * this.songList.length);
          壊す;
        デフォルト:
          if (type == "skipBack") {
            this.playIndex - 1 >= 0 ? this.playIndex-- : 0;
          } それ以外 {
            this.playIndex =
              this.playIndex + 1 >= this.songList.length
                ? この曲リストの長さ - 1
                : this.playIndex + 1;
          }
          壊す;
      }
      this.songInfo = this.songList[this.playIndex];
      this.getMusicList(this.songInfo.id);
      this.playing = true;
      タイムアウトを設定する(() => {
        this.$refs.rotate.style.animationPlayState = "実行中";
        音楽を再生します。
      }, 200);
    },
    //音量を調整する changeVolum(c) {
      音楽の音量をc/100に設定します。
      音楽の音量が0の場合
        this.volumeType = "md-volume-off";
      } それ以外 {
        this.volumeType = "md-volume-up";
      }
    },
    //再生する曲のURL情報を取得する getMusicList(id) {
      that = this とする;
      axios.get("/musicController/getMusicURLInfo/" + id).then(function (res) {
        スイッチ (res.code) {
          ケース "0000":
            that.songInfo.url = res.data.url;
            歌詞のリストを取得します。
            壊す;
          ケース「1111」:
            メッセージを表示します("警告", res.message);
            壊す;
        }
      });
    },
    歌詞リストを取得する(lrc) {
      lyricsObjArr = [] とします。
      const regNewLine = /\n/;
      const lineArr = lrc.split(regNewLine); // 各行の歌詞の配列 const regTime = /\[\d{2}:\d{2}.\d{2,3}\]/;
      lineArr.forEach((item) => {
        if (item === "") 戻り値:
        定数obj = {};
        定数時間 = item.match(regTime);
 
        obj.lyric =
          item.split("]")[1].trim() === "" ? "" : item.split("]")[1].trim();
        obj.time = 時間
          ? commonJs.TimeToSeconds(time[0].slice(1, time[0].length - 1))
          : 0;
        obj.uid = Math.random().toString().slice(-6);
        obj.lyric === "" の場合 {
          console.log("この行には歌詞がありません");
        } それ以外 {
          歌詞をObjArr.push(obj);
        }
      });
      this.lyricInfo = lyricsObjArr.map((item, index) => {
        アイテム.index = インデックス;
        戻る {
          ...アイテム、
        };
      });
    },
  },
};
</スクリプト>
 
<style lang="less" スコープ>
.メインページ {
  幅: 100%;
  高さ: 100%;
  位置: 絶対;
  背景: rgba(15, 15, 15, 0.4);
  オーバーフロー: 非表示;
  .background-flitter {
    位置: 絶対;
    zインデックス: 0;
    背景繰り返し: 繰り返しなし;
    幅: 100%;
    高さ: 100%;
    上: 0;
    左: 0;
    背景サイズ: カバー;
    背景位置: 50%;
    フィルター: ぼかし(8px);
    // マージン: -20px;
    不透明度: 0.7;
    オーバーフロー: 非表示;
    ボックスのサイズ: 境界線ボックス;
  }
  .play-mini {
    位置: 絶対;
    下部: 0;
    左: 0;
    幅: 100%;
    高さ: 72px;
    // 背景: #fff;
    ディスプレイ: フレックス;
    アイテムの位置を中央揃えにします。
    パディング: 6px 0;
    ボックスのサイズ: 境界線ボックス;
    zインデックス: 10;
    .songInfo{
      最小幅: 360px;
      最大幅: 480px;
      位置: 相対的;
      パディング: 0 18px;
      ボックスのサイズ: 境界線ボックス;
      ディスプレイ: フレックス;
      .ポスター{
        幅: 52px;
        高さ: 52px;
        境界線の半径: 5px;
        上マージン: 4px;
        右マージン: 20px;
      }
      。情報 {
        最小幅: 280px;
        高さ: 100%;
        行の高さ: 30px;
        フォントサイズ: 16px;
      }
    }
    .コントロール{
      幅: 280ピクセル;
      高さ: 100%;
      ディスプレイ: フレックス;
      アイテムの位置を中央揃えにします。
      画像 {
        幅: 40px;
        高さ: 40px;
        カーソル: ポインタ;
      }
      。状態 {
        幅: 40px;
        高さ: 40px;
        左マージン: 36px;
        右マージン: 36px;
        カーソル: ポインタ;
      }
    }
    .プログレスバー{
      位置: 絶対;
      zインデックス: 10;
      上: -5px;
      幅: 100%;
      高さ: 5px;
      背景: rgba(255, 255, 255, 0.5);
      カーソル: ポインタ;
      .progress-box {
        高さ: 100%;
        背景: #40ce8f;
        位置: 相対的;
      }
    }
    .右下{
      位置: 相対的;
      幅: 420ピクセル;
      高さ: 100%;
      ディスプレイ: フレックス;
      アイテムの位置を中央揃えにします。
      .text-div {
        色: #fff;
        高さ: 100%;
        行の高さ: 60px;
        左マージン: 5px;
        右マージン: 5px;
      }
      .プレイリスト{
        位置: 絶対;
        右: 0px;
      }
      {
        色: #333;
      }
    }
  }
  .song-cover-lyrics {
    位置: 相対的;
    幅: 100%;
    高さ: 100%;
    パディング下部: 72px;
    ボックスのサイズ: 境界線ボックス;
    ディスプレイ: フレックス;
    オーバーフロー: 非表示;
    .ディスクコンテナ{
      幅: 50%;
      高さ: 100%;
      位置: 相対的;
      .ポスター{
        位置: 相対的;
        幅: 280ピクセル;
        高さ: 280px;
        境界線の半径: 50%;
        背景: rgba(255, 255, 255, 0.3);
        左: 50%;
        上: 100px;
        左マージン: -140px;
        ボックスの影: 0 0 0 12px rgba(255, 255, 255, 0.4);
        アニメーション: animations1 12 秒の線形無限前進;
        アニメーション再生状態: 一時停止;
        オーバーフロー: 非表示;
        下部マージン: 160px;
        画像 {
          幅: 100%;
          高さ: 100%;
        }
      }
      .曲名{
        幅: 100%;
        高さ: 40px;
        テキスト配置: 中央;
        フォントサイズ: 32px;
        フォントの太さ: 600;
        色: #fff;
        行の高さ: 40px;
      }
      .song-artistsName {
        幅: 100%;
        高さ: 40px;
        テキスト配置: 中央;
        フォントサイズ: 28px;
        フォントの太さ: 600;
        色: #fff;
        行の高さ: 40px;
        上マージン: 24px;
      }
      @keyframesアニメーション1 {
        から {
          変換: 回転(0度);
        }
        に {
          変換: 回転(360度);
        }
      }
    }
    .歌詞{
      幅: 50%;
      高さ: 600px;
      位置: 相対的;
      オーバーフロー: 非表示;
    }
  }
}
</スタイル>
<スタイル lang="less">
.ivu-引き出し本体{
  .リストコンテナ{
    幅: 100%;
    高さ: 100%;
    オーバーフロー:自動;
    位置: 相対的;
    .songInfo{
      幅: 100%;
      高さ: 42px;
      ディスプレイ: フレックス;
      アイテムの位置を中央揃えにします。
      下部マージン: 12px;
      カーソル: ポインタ;
      画像 {
        幅: 36ピクセル;
        高さ: 36px;
        境界線の半径: 5px;
        右マージン: 12px;
      }
      。情報 {
        位置: 相対的;
        幅: 240ピクセル;
        高さ: 36px;
        行の高さ: 18px;
        。名前 {
          幅: 100%;
          高さ: 18px;
          フォントサイズ: 14px;
          フォントの太さ: 600;
          テキストオーバーフロー: 省略記号;
          オーバーフロー: 非表示;
          空白: ラップなし;
          行の高さ: 18px;
        }
        .歌手{
          幅: 100%;
          高さ: 18px;
          フォントサイズ: 12px;
          テキストオーバーフロー: 省略記号;
          オーバーフロー: 非表示;
          空白: ラップなし;
          行の高さ: 18px;
        }
      }
    }
  }
}
</スタイル>

歌詞部分 (lyricScroll.vue)

<テンプレート>
  <!--歌詞-->
  <div
    ref="音楽歌詞"
    クラス="音楽-歌詞"
    :style="{'padding-top': paddingTop}"
  >
    <div class="music-lyric-items" :style="lyricTop">
      <テンプレート v-if="歌詞リスト.length > 0">
        <p
          v-for="(item, index) in lyricsList"
          :key="インデックス"
          :data-index="インデックス"
          ref="歌詞"
          :style="{
            色: lyricIndex === インデックス? colorLight: 色、
            'フォントサイズ': フォントサイズ、
          }"
        >
          {{ item.lyric }}
        </p>
      </テンプレート>
      <p style="color: #fff" v-else>歌詞を読み込んでいます。 。 。 。 。 </p>
    </div>
  </div>
</テンプレート>
 
<スクリプト>
const COMPONENT_NAME = "スクロール";
 
エクスポートデフォルト{
  名前: COMPONENT_NAME、
  小道具: {
    // 歌詞リスト lyricsList: {
      タイプ: 配列、
      デフォルト: () => [],
    },
    // 現在の歌詞インデックス lyricIndex: {
      タイプ: 数値、
      デフォルト: 0,
    },
    // 歌詞のデフォルトの色 color: {
      タイプ: 文字列、
      デフォルト: "#fff",
    },
    // 歌詞のハイライト colorcolorLight: {
      タイプ: 文字列、
      デフォルト: "#40ce8f",
    },
    フォントサイズ: {
      タイプ: 文字列、
      デフォルト: "16px",
    },
    行の高さ: {
      タイプ: 文字列、
      デフォルト: "42",
    },
    パディングトップ: {
      タイプ: 文字列、
      デフォルト: "300px",
    },
  },
  データ() {
    戻る {
      top: 0, // 歌詞を中央に表示 // 歌詞リストの例 lyricListDemo: [
        {
          インデックス: 0,
          歌詞:「作曲:CMJ」
          時間: 0,
        },
        {
          インデックス: 1,
          歌詞:「作詞:タオ・ジウ」
          時間: 0.29、
        },
        {
          インデックス: 2,
          歌詞:「晩秋の落ち葉を聴く」
          時間: 0.89、
        },
        {
          インデックス: 3,
          歌詞:「さよならをため息とともに聞く」
          時間: 5.14、
        },
        {
          インデックス: 4,
          歌詞:「私はそれを鑑賞するために一人残された」
          時間: 9.39、
        },
        {
          インデックス: 5,
          歌詞:「海と山と風と月」
          時間: 13.14、
        },
      ]、
    };
  },
  マウント() {},
  時計:
    歌詞インデックス(新しい値、古い値) {},
  },
  計算: {
    歌詞トップ() {
      `transform :translate3d(0, ${(0 - this.lineHeight) * を返します
        (this.lyricIndex - this.top)}px, 0);色: ${this.color};行の高さ: ${
        this.lineHeight
      }px`;
    },
  },
  メソッド: {},
};
</スクリプト>
<style lang="less" スコープ>
/*歌詞部分*/
.音楽歌詞{
  パディング上部: 300px;
  ボックスのサイズ: 境界線ボックス;
  オーバーフロー: 非表示;
  テキスト配置: 中央;
  マスク画像: 線形グラデーション(
    一番下まで、
    RGBA(255, 255, 255, 0) 0,
    RGBA(255, 255, 255, 0.6) 5%,
    RGBA(255, 255, 255, 1) 15%,
    RGBA(255, 255, 255, 1) 85%,
    RGBA(255, 255, 255, 0.6) 95%,
    RGBA(255, 255, 255, 0) 100%
  );
  .music-lyric-items {
    テキスト配置: 中央;
    フォントサイズ: 16px;
    色: #fff;
    変換: translate3d(0, 0, 0);
    遷移: transform 0.6s イーズアウト;
    テキストオーバーフロー: 省略記号;
    オーバーフロー: 非表示;
    空白: ラップなし;
    。の上 {
      色: #40ce8f;
    }
  }
}
</スタイル>

時間変換JS (timeConversion.js)

/**
 * @著者 lyq
 * @時間 2021年11月21日 21:08:48
 *
 * 秒を時間、分、秒に変換します* @name TimeToString
 * @example 秒を時間、分、秒に変換します* @param {String} seconds 秒*/
const TimeToString = (秒) => {
    param = parseInt(秒)とします。
    hh = "", とします。
        ミリメートル = "",
        ss = "";
    パラメータ >= 0 && パラメータ < 60 の場合 {
        param < 10 ? (ss = "0" + param) : (ss = param);
        "00:" + ssを返します。
    } そうでない場合 (パラメータ >= 60 && パラメータ < 3600) {
        mm = parseInt(パラメータ / 60);
        mm < 10 ? (mm = "0" + mm) : mm;
        パラメータ - parseInt(mm * 60) < 10 ?
            (ss = "0" + String(param - parseInt(mm * 60))) :
            (ss = パラメータ - parseInt(mm * 60));
        mm + ":" + ssを返します。
    }
}

基本的なフロントエンドコードはここにあり、以下はバックエンドのインターフェースロジック層コードです。

/**
 * @著者: [LiuYanQiang]
 * @バージョン: [v1.0]
 * @クラス名: MusicServiceImpl
 * @description: [このクラスの機能の説明]
 * @createTime : [2021/11/16 14:28]
 * @updateUser : [LiuYanQiang]
 * @更新時間 : [2021/11/16 14:28]
 * @updateRemark: [この変更の説明]
 */
@サービス
翻訳者
パブリッククラス MusicServiceImpl は MusicService を実装します {
    オートワイヤード
    プライベート環境環境;
 
 
    /*
     * @バージョン V1.0
     * タイトル: getMusicList
     * @author 劉燕強
     * @description ホットソングリストのランダムな20曲の情報を取得します* @createTime 2021/11/16 14:32
     * @パラメータ []
     * @return java.util.Map*/
    @オーバーライド
    パブリックリスト<Map<文字列、オブジェクト>> getMusicList() {
        JSONArray 結果オブジェクト = null;
        // URL を連結し、対応するリクエストを送信します。StringBuffer url = new StringBuffer();
        url.append("https://api.vvhan.com/api/rand.music?type=all&sort=Hot Song List");
        // インターフェイスの戻り値を取得します。String body = HttpUtils.sendGet(url.toString());
        結果オブジェクト = JSONObject.parseArray(body);
        リスト<Map<String, Object>> リスト = 新しい ArrayList<>();
        (int i = 0; i < resultObject.size(); i++) の場合 {
            HashMap<String, Object> マップ = 新しい HashMap<String, Object>();
            JSONオブジェクト jsonObject = resultObject.getJSONObject(i);
            map.put("カバー", JSONObject.parseObject(jsonObject.get("アルバム").toString()).getString("picUrl"));
            map.put("アーティスト名", JSONObject.parseArray(jsonObject.get("アーティスト").toString()).getJSONObject(0).getString("名前"));
            map.put("名前", jsonObject.getString("名前"));
            map.put("id", jsonObject.getString("id"));
            リストにマップを追加します。
        }
        ランダム random = new Random();
        int num = random.nextInt(179) % (179 - 0 + 1) + 0;
        リスト = list.subList(num, num + 20);
        リストを返します。
    }
 
    /*
     * @バージョン V1.0
     * タイトル: getMusicURLInfo
     * @author 劉燕強
     * @description 音楽プレーヤーのURL情報を取得します * @createTime 2021/11/19 9:22
     * @param [Id——音楽ID]
     * @return java.util.List<java.util.Map<java.lang.String,java.lang.Object>>*/
    @オーバーライド
    パブリックマップ<String, Object> getMusicURLInfo(String Id) {
        JSONオブジェクト結果オブジェクト = null;
        // URL を連結し、対応するリクエストを送信します。StringBuffer url = new StringBuffer();
        url.append("https://api.vvhan.com/api/music?id=" + Id + "&type=song&media=netease");
        // インターフェイスの戻り値を取得します。String body = HttpUtils.sendGet(url.toString());
        結果オブジェクト = JSONObject.parseObject(本文);
        HashMap<String, Object> マップ = 新しい HashMap<String, Object>();
        //第三者から提供された音楽URLが有効かどうかを判断します。無効の場合は公式URLに置き換えます
        if(this.isValid(resultObject.get("mp3url").toString())){
            map.put("id", resultObject.get("song_id").toString());
            map.put("名前", resultObject.get("名前"));
            map.put("アーティスト名", resultObject.get("著者"));
            map.put("カバー", resultObject.get("カバー"));
            map.put("url", resultObject.get("mp3url"));
            map.put("歌詞", this.getMusicLyricById(Id) != null ? this.getMusicLyricById(Id) : null);
        }
        それ以外{
            map.put("id", Id);
            map.put("url", "https://music.163.com/song/media/outer/url?id="+Id+".mp3");
            map.put("歌詞", this.getMusicLyricById(Id) != null ? this.getMusicLyricById(Id) : null);
        }
        マップを返します。
    }
 
    /*
     * @バージョン V1.0
     * タイトル: isValid
     * @author 劉燕強
     * @description リンクが有効かどうかを判定する* @createTime 2021/11/20 10:23
     * @param [strLink——入力リンク]
     * @return ブール値
     * */
    パブリックブール値isValid(文字列strLink) {
        URL URL;
        試す {
            url = 新しいURL(strLink);
            HttpURLConnection 接続 = (HttpURLConnection) url.openConnection();
            connt.setRequestMethod("HEAD");
            文字列 strMessage = connt.getResponseMessage();
            if (strMessage.compareTo("見つかりません") == 0) {
                false を返します。
            }
            接続を切断します。
        } キャッチ (例外 e) {
            false を返します。
        }
        true を返します。
    }
 
    /*
     * @バージョン V1.0
     * タイトル: getRandomFiveMusic
     * @author 劉燕強
     * @description 5曲をランダムに再生します。頻繁に呼び出さないでください。そうしないと、NetEase Cloud APIコールバックが異常になります。 * @createTime 2021/11/19 9:08
     * @パラメータ []
     * @return java.util.List<java.util.Map<java.lang.String,java.lang.Object>>*/
    @オーバーライド
    パブリックリスト<Map<文字列、オブジェクト>> getRandomFiveMusic() {
        リスト<Map<String, Object>> リスト = 新しい ArrayList<>();
        (int i = 0; i < 5; i++) の場合 {
            JSONオブジェクト結果オブジェクト = null;
            // URL を連結し、対応するリクエストを送信します。StringBuffer url = new StringBuffer();
            url.append("https://api.vvhan.com/api/rand.music?type=json&sort=Hot Song List");
            // インターフェイスの戻り値を取得します。String body = HttpUtils.sendGet(url.toString());
            結果オブジェクト = JSONObject.parseObject(本文);
            JSONObject 情報 = JSONObject.parseObject(resultObject.get("info").toString());
            HashMap<String, Object> マップ = 新しい HashMap<String, Object>();
            map.put("id", info.get("id").toString());
            map.put("名前"、info.get("名前"));
            map.put("アーティスト名", info.get("作者"));
            map.put("カバー", info.get("picUrl"));
            map.put("url", info.get("mp3url"));
            map.put("歌詞", this.getMusicLyricById(info.get("id").toString()) != null ? this.getMusicLyricById(info.get("id").toString()) : null);
            リストにマップを追加します。
            log.info("呼び出しは成功しました" + i + "回");
        }
        リストを返します。
    }
 
    /*
     * @バージョン V1.0
     * タイトル: getMusicLyricById
     * @author 劉燕強
     * @description 歌詞情報を取得* @createTime 2021/11/16 19:23
     * @param [Id——音楽ID]
     * @return java.lang.String*/
    @オーバーライド
    パブリック文字列 getMusicLyricById(文字列 ID) {
        試す {
            JSONオブジェクト結果オブジェクト = null;
            // URL を連結し、対応するリクエストを送信します。StringBuffer url = new StringBuffer();
            url.append("https://music.163.com/api/song/media?id=" + Id);
            // インターフェイスの戻り値を取得します。String body = HttpUtils.sendGet(url.toString());
            結果オブジェクト = JSONObject.parseObject(本文);
            (resultObject.get("lyric").toString() != null) の場合 {
                resultObject.get("lyric").toString() を返します。
            } それ以外 {
                null を返します。
            }
        } キャッチ (例外 e) {
            e.printStackTrace();
        }
        null を返します。
    }
}

要約する

これで、NetEase Cloud Music Player インターフェースを模倣した Vue の簡単な実装に関するこの記事は終了です。Vue NetEase Cloud Music Player インターフェースの関連コンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、次の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM を応援していただければ幸いです。

以下もご興味があるかもしれません:
  • Vuejs は NetEase Cloud Music を模倣して、視聴と検索機能を実現します
  • Vueで実装されたNetEase Cloud Musicのオンライン再生とダウンロード機能の例
  • VueはNetEase Cloud Musicのシングルページアプリケーションを模倣する
  • mpvue N​​etEase Cloud SMS インターフェースを使用してミニプログラムの SMS ログインを実装するためのサンプル コード

<<:  ウェブサイト標準開発フローチャート

>>:  ウェブページにプレーヤーを埋め込む埋め込み要素の自動開始が false 無効

推薦する

画像を使用してハイパーリンクのパーソナライズされた下線を実現します

画像内に下線付きのリンクが表示されても驚かないでください。実はとても簡単なので、あなたにもできるので...

Homebrewを使用してMacにMySQLをインストールするときにログインできない問題を解決する

お使いのコンピュータが Mac の場合、homebrew を使用して MySQL をインストールする...

Linux 3.X/4.x/5.x でパゴダ パネルのパスワードを忘れた場合の解決方法

ssh に入り、次のコマンドを入力してパスワードをリセットします (コマンドの末尾の「testpas...

a タグをクリックして入力ファイルのアップロードダイアログボックスを表示する方法

htmlコードをコピーコードは次のとおりです。 <SPAN class=tag><...

今日は、珍しいけれど役に立つJSテクニックをいくつか紹介します

1. 戻るボタンhistory.back() を使用してブラウザの「戻る」ボタンを作成します。 &l...

Dockerイントラネット侵入FRP展開の実装プロセスの分析

1. 設定ファイルディレクトリを作成するcd /ホームディレクトリmkdir frp最終的なディレク...

Vue コンポーネントはどのように解析され、レンダリングされるのでしょうか?

序文この記事では、Vue コンポーネントがどのように解析され、レンダリングされるかを説明します。 V...

SQL 実装 LeetCode (185. 部門内で最も給与の高い上位 3 名)

[LeetCode] 185. 部門別給与上位3位従業員テーブルにはすべての従業員が保持されます。...

MySQL Index Pushdown (ICP) とは何かを理解するための記事

目次1. はじめに2. 原則III. 実践3.1 インデックスプッシュダウンを使用しない3.2 イン...

HTML Web ページにおける URL の表現

HTML では、一般的な URL はさまざまな方法で表現されます。相対 URL:コードをコピーコード...

Linux ホスト名設定の詳細な紹介

目次1. Linuxホスト名を設定するクライアントホストを構成するサーバーホストを構成する2. ホス...

Mysql テーブル、列、データベースの追加、削除、変更、クエリの問題の概要

以下は私がまとめた基本的なSQL知識です。主に参考資料として、また将来の他の初心者の助けとして、私自...

HTML の blockquote タグの使用と美化

ブロック引用の定義と使用法<blockquote> タグは引用ブロックを定義します。 &...

MySQL 論理バックアップとリカバリ テストの概要

目次1. データベース論理バックアップとはどのようなバックアップですか? 2. よく使われる論理バッ...

CSS を解析して画像のテーマカラー機能を抽出する (ヒント)

背景すべては、WeChat 技術グループのクラスメートが「写真の主な色を取得する方法はあるか」と尋ね...