vue仿网易云音乐播放器界面的简单实现过程

由于工作项目的需要,需要使用到歌曲播放,参考多方资料,写了一个仿网易云音乐播放界面,能完整的实现音乐播放功能。

前端简单的使用vue组件和audio标签实现了播放器界面,后端则是调用网易云的API获取对应的歌曲信息。

 废话不多说上代码

歌曲播放界面(musicPlay.vue)

<template>
  <div class="main-page">
    <audio :src="songInfo.url" id="music" autoplay="autoplay"></audio>
    <div
      class="background-flitter"
      :style="`background-image: url(${songInfo.cover})`"
    ></div>
    <div class="play-mini">
      <div class="progress-bar" @click="handleProgressClick" ref="track">
        <div
          class="progress-box"
          :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:;">
            <Icon
              type="md-skip-backward"
              @click="skipBack"
              size="26"
              color="white"
            />
          </a>
        </Tooltip>
        <!-- 播放暂停 -->
        <Tooltip content="播放暂停" theme="light" :delay="1500">
          <img
            @click="playMusic"
            class="status"
            v-show="!playing"
            src="@/assets/play_icon.png"
            alt=""
          />
          <img
            class="status"
            @click="playMusic"
            v-show="playing"
            src="@/assets/play-02.png"
            alt=""
          />
        </Tooltip>
        <!-- 下一首提示 -->
        <Tooltip content="下一首" theme="light" :delay="1500">
          <a href="javascript:;">
            <Icon
              type="md-skip-forward"
              @click="skipForward"
              size="26"
              color="white"
            />
          </a>
        </Tooltip>
      </div>
      <div class="right-botton">
        <div class="text-div"></div>
        <!-- 音量 -->
        <a href="javascript:;">
          <Icon
            :type="volumeType"
            size="26"
            color="white"
            @click="volumeChange"
          />
        </a>
        <div class="text-div"></div>
        <Slider
          style="width: 80px; z-index: 99999"
          @on-input="changeVolum"
          v-model="volume"
        ></Slider>
        <div class="text-div"></div>
        <div class="text-div"></div>
        <div class="text-div"></div>
        <!-- 歌曲播放类型 -->
        <Tooltip :content="showPlayType" theme="light" :delay="1500">
          <a href="javascript:;">
            <Icon
              :custom="playStatus"
              @click="playTypeChange"
              size="26"
              color="white"
            />
          </a>
        </Tooltip>
        <div class="text-div"></div>
        <div class="text-div"></div>
        <div class="playlist">
          <!-- 播放列表 -->
          <Tooltip content="列表" theme="light" :delay="1500">
            <a href="javascript:;">
              <Icon
                custom="iconfont icon-bofangqi-xuanji"
                @click="drawer = true"
                size="36"
                color="white"
              />
            </a>
          </Tooltip>
        </div>
      </div>
    </div>
    <div class="song-cover-lyric">
      <div class="disc-continer">
        <div class="poster" ref="rotate">
          <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="lyric"
          :color="color"
          :colorLight="colorLight"
          :lineHeight="lineHeight"
          :paddingTop="paddingTop"
          :fontSize="fontSize"
          :lyricIndex="lyricIndex"
          :lyricsList="lyricInfo"
        ></mscroll>
      </div>
    </div>
    <Drawer
      title="播放列表"
      placement="left"
      width="320"
      :closable="false"
      v-model="drawer"
    >
      <div class="list-container">
        <div
          class="songInfo"
          v-for="(item, index) in songList"
          :key="index"
          @click="PlayListMusic(index)"
        >
          <img :src="item.cover" alt="" />
          <div class="info">
            <div class="name">{{ item.name }}</div>
            <div class="singer">{{ item.artistsName }}</div>
          </div>
        </div>
      </div>
    </Drawer>
  </div>
</template>
<script>
import { showMessage } from "../../publicMethod/publicMethods";
import Mscroll from "./lyricScroll.vue";
import commonJs from "../../utils/timeConversion";
import axios from "axios";
export default {
  data() {
    return {
      volumeNum: 80, //暂存的音量
      volumeStatus: true, //音量图标的变化
      volumeType: "md-volume-up", //音量图标
      playStatus: "iconfont icon-xunhuanbofang", //播放类型图标
      playing: false,
      drawer: false,
      playIndex: 0,
      songInfo: {},
      songList: [],
      volume: 80, // 音量
      lyricInfo: [],
      playType: 1, // 播放类型:1-列表循环,2-随机播放,3-单曲循环
      showPlayType: "列表循环",
      audioProgress: 0,
      thumbTranslateX: 0,
      lyricIndex: 0,
      color: "#fff", //歌词默认颜色
      colorLight: "#40ce8f", //歌词高亮色
      fontSize: "16px", //歌词字体大小
      lineHeight: "42", //每段行高
      paddingTop: "300px", //高亮歌词部分居中
    };
  },
  created() {},
  components: {
    Mscroll,
  },
  computed: {
    audioProgressPercent() {
      return `${this.audioProgress * 100}%`;
    },
  },
  mounted() {
    const music = document.getElementById("music");
    if (this.$route.query.play) {
      this.ClickPlay();
    } else {
this.GetSongList();
    }

    if (this.playing) {
      // 播放中,点击则为暂停
      this.playing = false;
      this.$refs.rotate.style.animationPlayState = "paused";
      music.pause();
    } else {
      // 暂停中,点击则为播放
      this.playing = true;
      this.$refs.rotate.style.animationPlayState = "running";
      music.play();
    }
  },
  methods: {
    //音量变化
    volumeChange() {
      if (this.volumeStatus) {
        this.volumeStatus = false;
        this.volumeNum = this.volume;
        this.volume = 0;
        this.volumeType = "md-volume-off";
      } else {
        this.volumeStatus = true;
        this.volume = this.volumeNum;
        this.volumeType = "md-volume-up";
      }
    },
    //歌曲播放类型变化
    playTypeChange() {
      if (this.playType == 1) {
        this.playType = 2;
        this.showPlayType = "随机播放";
        this.playStatus = "iconfont icon-suijibofang";
        return;
      }
      if (this.playType == 2) {
        this.playType = 3;
        this.showPlayType = "单曲循环";
        this.playStatus = "iconfont icon-danquxunhuan";
        return;
      }
      if (this.playType == 3) {
        this.playType = 1;
        this.showPlayType = "列表循环";
        this.playStatus = "iconfont icon-xunhuanbofang";
        return;
      }
    },
    ClickPlay() {
      this.audioInit();
      this.getMusicList(this.songInfo.id);
      this.$refs.rotate.style.animationPlayState = "running";
      this.playing = true;
      setTimeout(() => {
        music.play();
      }, 100);
    },
    GetSongList() {
      axios.get("/musicController/getMusicList").then(this.GetSongListInfo);
    },
    GetSongListInfo(res) {
      let myList;
      if (res.code == "0000") {
        myList = res.data;
      } else {
        console.log("没查到数据");
        myList = [
          {
            artistsName: "房东的猫",
            cover:
              "https://p3.music.126.net/KkrcSwKbRsd8GuaOHILlxA==/109951166077317301.jpg",
            id: 1857630559,
            name: "New Boy",
            url: "https://music.163.com/song/media/outer/url?id=1857630559.mp3",
            lyric:
              "\n[00:25.075]\n[00:25.189]是的我看见到处是阳光\n[00:29.156]快乐在城市上空飘扬\n[00:32.773]新世界来得像梦一样\n[00:36.689]让我暖洋洋\n[00:40.122]你的老怀表还在转吗\n[00:43.822]你的旧皮鞋还能穿吗\n[00:47.506]这儿有一支未来牌香烟\n[00:51.479]你不想尝尝吗\n[00:54.512]明天一早 我猜阳光会好\n[01:02.679]我要把自己打扫\n[01:05.896]把破旧的全部卖掉\n[01:09.212]哦这样多好 快来吧奔腾电脑\n[01:17.329]就让它们代替我来思考\n[01:27.229]穿新衣吧 剪新发型呀\n[01:31.347]轻松一下Windows98\n[01:35.048]打扮漂亮 18岁是天堂\n[01:39.064]我们的生活甜得像糖\n[01:42.431]穿新衣吧 剪新发型呀\n[01:46.098]轻松一下Windows98\n[01:49.914]以后的路不再会有痛苦\n[01:53.948]我们的未来该有多酷\n[02:12.481]是的我看见到处是阳光\n[02:16.164]快乐在城市上空飘扬\n[02:19.847]新世界来的像梦一样\n[02:23.748]让我暖洋洋\n[02:27.164]你的老怀表还在转吗\n[02:30.815]你的旧皮鞋还能穿吗\n[02:34.614]这儿有一支未来牌香烟\n[02:38.448]你不想尝尝吗\n[02:41.548]明天一早我猜阳光会好\n[02:49.898]我要把自己打扫\n[02:53.564]把破旧的全部卖掉\n[02:56.198]哦这样多好 快来吧奔腾电脑\n[03:04.598]就让它们代替我来思考\n[03:11.081]\n[03:11.414]穿新衣吧剪新发型呀\n[03:14.698]轻松一下Windows98\n[03:18.264]打扮漂亮18岁是天堂\n[03:22.481]我们的生活甜得像糖\n[03:25.964]穿新衣吧剪新发型呀\n[03:29.515]轻松一下Windows98\n[03:33.264]以后的路不再会有痛苦\n[03:37.681]我们的未来该有多酷",
          },
        ];
      }
      this.songList = myList;
      this.songInfo = this.songList[0];
      this.getMusicList(this.songInfo.id); //通过正在播放的歌曲id获取歌曲播放的URL歌词信息
      this.audioInit();
    },
    audioInit() {
      let that = this;
      let progressL = this.$refs.track.offsetWidth; // 进度条总长
      music.addEventListener("timeupdate", () => {
        // 当前播放时间
        let compareTime = music.currentTime;
        for (let i = 0; i < that.lyricInfo.length; i++) {
          if (compareTime > parseInt(that.lyricInfo[i].time)) {
            const index = 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("ended", () => {
        switch (parseInt(that.playType)) {
          case 1: // 列表循环
            that.playIndex =
              that.playIndex + 1 >= that.songList.length
                ? 0
                : that.playIndex + 1;
            break;
          case 2: // 随机播放
            that.playIndex = Math.floor(Math.random() * that.songList.length);
            break;
          case 3: // 单曲循环
            break;
        }
        that.songInfo = that.songList[that.playIndex];
        this.getMusicList(that.songInfo.id);
        setTimeout(() => {
          this.$refs.rotate.style.animationPlayState = "running";
          music.play();
        }, 200);
      });
    },
    //播放与暂停
    playMusic() {
      if (this.playing) {
        // 播放中,点击则为暂停
        this.playing = false;
        this.$refs.rotate.style.animationPlayState = "paused";
        music.pause();
      } else {
        // 暂停中,点击则为播放
        this.playing = true;
        this.$refs.rotate.style.animationPlayState = "running";
        music.play();
      }
    },
    PlayListMusic(index) {
      this.playIndex = index;
      this.songInfo = this.songList[this.playIndex];
      this.getMusicList(this.songInfo.id);
      this.playing = true;
      this.drawer = false;
      setTimeout(() => {
        this.$refs.rotate.style.animationPlayState = "running";
        music.play();
      }, 200);
    },
    //点击进度条
    handleProgressClick(event) {
      let progressL = this.$refs.track.offsetWidth; // 进度条总长
      let clickX = event.offsetX;
      let time = (clickX / progressL).toFixed(2);
      this.setProgress(time);
    },
    setProgress(x) {
      music.currentTime = music.duration * x;
    },
    // 上一首
    skipBack() {
      this.skipFn("skipBack");
    },
    // 下一首
    skipForward() {
      this.skipFn("skipForward");
    },
    //上下首封装
    skipFn(type) {
      switch (parseInt(this.playType)) {
        case 2: // 随机播放
          this.playIndex = Math.floor(Math.random() * this.songList.length);
          break;
        default:
          if (type == "skipBack") {
            this.playIndex - 1 >= 0 ? this.playIndex-- : 0;
          } else {
            this.playIndex =
              this.playIndex + 1 >= this.songList.length
                ? this.songList.length - 1
                : this.playIndex + 1;
          }
          break;
      }
      this.songInfo = this.songList[this.playIndex];
      this.getMusicList(this.songInfo.id);
      this.playing = true;
      setTimeout(() => {
        this.$refs.rotate.style.animationPlayState = "running";
        music.play();
      }, 200);
    },
    //调节音量
    changeVolum(c) {
      music.volume = c / 100;
      if (music.volume == 0) {
        this.volumeType = "md-volume-off";
      } else {
        this.volumeType = "md-volume-up";
      }
    },
    //获取歌曲播放的URL信息
    getMusicList(id) {
      let that = this;
      axios.get("/musicController/getMusicURLInfo/" + id).then(function (res) {
        switch (res.code) {
          case "0000":
            that.songInfo.url = res.data.url;
            that.GetLyricList(res.data.lyric);
            break;
          case "1111":
            showMessage("warning", res.message);
            break;
        }
      });
    },
    GetLyricList(lrc) {
      let lyricsObjArr = [];
      const regNewLine = /\n/;
      const lineArr = lrc.split(regNewLine); // 每行歌词的数组
      const regTime = /\[\d{2}:\d{2}.\d{2,3}\]/;
      lineArr.forEach((item) => {
        if (item === "") return;
        const obj = {};
        const time = item.match(regTime);

        obj.lyric =
          item.split("]")[1].trim() === "" ? "" : item.split("]")[1].trim();
        obj.time = time
          ? commonJs.TimeToSeconds(time[0].slice(1, time[0].length - 1))
          : 0;
        obj.uid = Math.random().toString().slice(-6);
        if (obj.lyric === "") {
          console.log("这一行没有歌词");
        } else {
          lyricsObjArr.push(obj);
        }
      });
      this.lyricInfo = lyricsObjArr.map((item, index) => {
        item.index = index;
        return {
          ...item,
        };
      });
    },
  },
};
</script>

<style lang="less" scoped>
.main-page {
  width: 100%;
  height: 100%;
  position: absolute;
  background: rgba(15, 15, 15, 0.4);
  overflow: hidden;
  .background-flitter {
    position: absolute;
    z-index: 0;
    background-repeat: no-repeat;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    background-size: cover;
    background-position: 50%;
    filter: blur(8px);
    // margin: -20px;
    opacity: 0.7;
    overflow: hidden;
    box-sizing: border-box;
  }
  .play-mini {
    position: absolute;
    bottom: 0;
    left: 0;
    width: 100%;
    height: 72px;
    // background: #fff;
    display: flex;
    align-items: center;
    padding: 6px 0;
    box-sizing: border-box;
    z-index: 10;
    .songInfo {
      min-width: 360px;
      max-width: 480px;
      position: relative;
      padding: 0 18px;
      box-sizing: border-box;
      display: flex;
      .poster {
        width: 52px;
        height: 52px;
        border-radius: 5px;
        margin-top: 4px;
        margin-right: 20px;
      }
      .info {
        min-width: 280px;
        height: 100%;
        line-height: 30px;
        font-size: 16px;
      }
    }
    .controls {
      width: 280px;
      height: 100%;
      display: flex;
      align-items: center;
      img {
        width: 40px;
        height: 40px;
        cursor: pointer;
      }
      .status {
        width: 40px;
        height: 40px;
        margin-left: 36px;
        margin-right: 36px;
        cursor: pointer;
      }
    }
    .progress-bar {
      position: absolute;
      z-index: 10;
      top: -5px;
      width: 100%;
      height: 5px;
      background: rgba(255, 255, 255, 0.5);
      cursor: pointer;
      .progress-box {
        height: 100%;
        background: #40ce8f;
        position: relative;
      }
    }
    .right-botton {
      position: relative;
      width: 420px;
      height: 100%;
      display: flex;
      align-items: center;
      .text-div {
        color: #fff;
        height: 100%;
        line-height: 60px;
        margin-left: 5px;
        margin-right: 5px;
      }
      .playlist {
        position: absolute;
        right: 0px;
      }
      a {
        color: #333;
      }
    }
  }
  .song-cover-lyric {
    position: relative;
    width: 100%;
    height: 100%;
    padding-bottom: 72px;
    box-sizing: border-box;
    display: flex;
    overflow: hidden;
    .disc-continer {
      width: 50%;
      height: 100%;
      position: relative;
      .poster {
        position: relative;
        width: 280px;
        height: 280px;
        border-radius: 50%;
        background: rgba(255, 255, 255, 0.3);
        left: 50%;
        top: 100px;
        margin-left: -140px;
        box-shadow: 0 0 0 12px rgba(255, 255, 255, 0.4);
        animation: animations1 12s linear infinite forwards;
        animation-play-state: paused;
        overflow: hidden;
        margin-bottom: 160px;
        img {
          width: 100%;
          height: 100%;
        }
      }
      .song-name {
        width: 100%;
        height: 40px;
        text-align: center;
        font-size: 32px;
        font-weight: 600;
        color: #fff;
        line-height: 40px;
      }
      .song-artistsName {
        width: 100%;
        height: 40px;
        text-align: center;
        font-size: 28px;
        font-weight: 600;
        color: #fff;
        line-height: 40px;
        margin-top: 24px;
      }
      @keyframes animations1 {
        from {
          transform: rotate(0deg);
        }
        to {
          transform: rotate(360deg);
        }
      }
    }
    .lyric {
      width: 50%;
      height: 600px;
      position: relative;
      overflow: hidden;
    }
  }
}
</style>
<style lang="less">
.ivu-drawer-body {
  .list-container {
    width: 100%;
    height: 100%;
    overflow: auto;
    position: relative;
    .songInfo {
      width: 100%;
      height: 42px;
      display: flex;
      align-items: center;
      margin-bottom: 12px;
      cursor: pointer;
      img {
        width: 36px;
        height: 36px;
        border-radius: 5px;
        margin-right: 12px;
      }
      .info {
        position: relative;
        width: 240px;
        height: 36px;
        line-height: 18px;
        .name {
          width: 100%;
          height: 18px;
          font-size: 14px;
          font-weight: 600;
          text-overflow: ellipsis;
          overflow: hidden;
          white-space: nowrap;
          line-height: 18px;
        }
        .singer {
          width: 100%;
          height: 18px;
          font-size: 12px;
          text-overflow: ellipsis;
          overflow: hidden;
          white-space: nowrap;
          line-height: 18px;
        }
      }
    }
  }
}
</style>

歌词部分(lyricScroll.vue)

<template>
  <!--歌词-->
  <div
    ref="musicLyric"
    class="music-lyric"
    :style="{ 'padding-top': paddingTop }"
  >
    <div class="music-lyric-items" :style="lyricTop">
      <template v-if="lyricsList.length > 0">
        <p
          v-for="(item, index) in lyricsList"
          :key="index"
          :data-index="index"
          ref="lyric"
          :style="{
            color: lyricIndex === index ? colorLight : color,
            'font-size': fontSize,
          }"
        >
          {{ item.lyric }}
        </p>
      </template>
      <p style="color: #fff" v-else>歌词拼命加载中。。。。。</p>
    </div>
  </div>
</template>

<script>
const COMPONENT_NAME = "scroll";

export default {
  name: COMPONENT_NAME,
  props: {
    // 歌词列表
    lyricsList: {
      type: Array,
      default: () => [],
    },
    // 当前歌词下标索引
    lyricIndex: {
      type: Number,
      default: 0,
    },
    // 歌词默认色
    color: {
      type: String,
      default: "#fff",
    },
    // 歌词高亮色
    colorLight: {
      type: String,
      default: "#40ce8f",
    },
    fontSize: {
      type: String,
      default: "16px",
    },
    lineHeight: {
      type: String,
      default: "42",
    },
    paddingTop: {
      type: String,
      default: "300px",
    },
  },
  data() {
    return {
      top: 0, // 歌词居中
      //歌词list示例
      lyricListDemo: [
        {
          index: 0,
          lyric: "作曲 : CMJ",
          time: 0,
        },
        {
          index: 1,
          lyric: "作词 : 桃玖",
          time: 0.29,
        },
        {
          index: 2,
          lyric: "你听啊秋末的落叶",
          time: 0.89,
        },
        {
          index: 3,
          lyric: "你听它叹息着离别",
          time: 5.14,
        },
        {
          index: 4,
          lyric: "只剩我独自领略",
          time: 9.39,
        },
        {
          index: 5,
          lyric: "海与山 风和月",
          time: 13.14,
        },
      ],
    };
  },
  mounted() {},
  watch: {
    lyricIndex(newVal, oldVal) {},
  },
  computed: {
    lyricTop() {
      return `transform :translate3d(0, ${(0 - this.lineHeight) *
        (this.lyricIndex - this.top)}px, 0);color: ${this.color};line-height: ${
        this.lineHeight
      }px`;
    },
  },
  methods: {},
};
</script>
<style lang="less" scoped>
/*歌词部分*/
.music-lyric {
  padding-top: 300px;
  box-sizing: border-box;
  overflow: hidden;
  text-align: center;
  mask-image: linear-gradient(
    to bottom,
    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 {
    text-align: center;
    font-size: 16px;
    color: #fff;
    transform: translate3d(0, 0, 0);
    transition: transform 0.6s ease-out;
    text-overflow: ellipsis;
    overflow: hidden;
    white-space: nowrap;
    .on {
      color: #40ce8f;
    }
  }
}
</style>

时间转换的JS(timeConversion.js)

/**
 * @author lyq
 * @time 2021年11月21日21:08:48
 *
 * 秒值转时分秒
 * @name TimeToString
 * @example 秒值转时分秒
 * @param {String} seconds 秒
 */
const TimeToString = (seconds) => {
    let param = parseInt(seconds);
    let hh = "",
        mm = "",
        ss = "";
    if (param >= 0 && param < 60) {
        param < 10 ? (ss = "0" + param) : (ss = param);
        return "00:" + ss;
    } else if (param >= 60 && param < 3600) {
        mm = parseInt(param / 60);
        mm < 10 ? (mm = "0" + mm) : mm;
        param - parseInt(mm * 60) < 10 ?
            (ss = "0" + String(param - parseInt(mm * 60))) :
            (ss = param - parseInt(mm * 60));
        return mm + ":" + ss;
    }
}

基本前端代码都在这儿了,下面为后端的接口逻辑层代码

/**
 * @author : [LiuYanQiang]
 * @version : [v1.0]
 * @className : MusicServiceImpl
 * @description : [描述说明该类的功能]
 * @createTime : [2021/11/16 14:28]
 * @updateUser : [LiuYanQiang]
 * @updateTime : [2021/11/16 14:28]
 * @updateRemark : [描述说明本次修改内容]
 */
@Service
@Slf4j
public class MusicServiceImpl implements MusicService {
    @Autowired
    private Environment environment;

    /*
     * @version V1.0
     * Title: getMusicList
     * @author LiuYanQiang
     * @description 获取热歌榜随机二十首音乐信息
     * @createTime  2021/11/16 14:32
     * @param []
     * @return java.util.Map*/
    @Override
    public List<Map<String, Object>> getMusicList() {
        JSONArray resultObject = null;
        //拼接URL发送对应的请求
        StringBuffer url = new StringBuffer();
        url.append("https://api.vvhan.com/api/rand.music?type=all&sort=热歌榜");
        //获取接口的返回值
        String body = HttpUtils.sendGet(url.toString());
        resultObject = JSONObject.parseArray(body);
        List<Map<String, Object>> list = new ArrayList<>();
        for (int i = 0; i < resultObject.size(); i++) {
            HashMap<String, Object> map = new HashMap<String, Object>();
            JSONObject jsonObject = resultObject.getJSONObject(i);
            map.put("cover", JSONObject.parseObject(jsonObject.get("album").toString()).getString("picUrl"));
            map.put("artistsName", JSONObject.parseArray(jsonObject.get("artists").toString()).getJSONObject(0).getString("name"));
            map.put("name", jsonObject.getString("name"));
            map.put("id", jsonObject.getString("id"));
            list.add(map);
        }
        Random random = new Random();
        int num = random.nextInt(179) % (179 - 0 + 1) + 0;
        list = list.subList(num, num + 20);
        return list;
    }

    /*
     * @version V1.0
     * Title: getMusicURLInfo
     * @author LiuYanQiang
     * @description 获取音乐播放的URL信息
     * @createTime  2021/11/19 9:22
     * @param [Id——音乐Id]
     * @return java.util.List<java.util.Map<java.lang.String,java.lang.Object>>*/
    @Override
    public Map<String, Object> getMusicURLInfo(String Id) {
        JSONObject resultObject = 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());
        resultObject = JSONObject.parseObject(body);
        HashMap<String, Object> map = new HashMap<String, Object>();
        //判断第三方给的音乐URL是否有效,无效则替换官方的URL
        if(this.isValid(resultObject.get("mp3url").toString())){
            map.put("id", resultObject.get("song_id").toString());
            map.put("name", resultObject.get("name"));
            map.put("artistsName", resultObject.get("author"));
            map.put("cover", resultObject.get("cover"));
            map.put("url", resultObject.get("mp3url"));
            map.put("lyric", this.getMusicLyricById(Id) != null ? this.getMusicLyricById(Id) : null);
        }
        else{
            map.put("id", Id);
            map.put("url", "https://music.163.com/song/media/outer/url?id="+Id+".mp3");
            map.put("lyric", this.getMusicLyricById(Id) != null ? this.getMusicLyricById(Id) : null);
        }
        return map;
    }

    /*
     * @version V1.0
     * Title: isValid
     * @author LiuYanQiang
     * @description 判断链接是否有效
     * @createTime  2021/11/20 10:23
     * @param [strLink——输入链接]
     * @return boolean
     * */
    public boolean isValid(String strLink) {
        URL url;
        try {
            url = new URL(strLink);
            HttpURLConnection connt = (HttpURLConnection) url.openConnection();
            connt.setRequestMethod("HEAD");
            String strMessage = connt.getResponseMessage();
            if (strMessage.compareTo("Not Found") == 0) {
                return false;
            }
            connt.disconnect();
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    /*
     * @version V1.0
     * Title: getRandomFiveMusic
     * @author LiuYanQiang
     * @description 随机5首音乐,不能频繁调用,不然网易云接口回调异常
     * @createTime  2021/11/19 9:08
     * @param []
     * @return java.util.List<java.util.Map<java.lang.String,java.lang.Object>>*/
    @Override
    public List<Map<String, Object>> getRandomFiveMusic() {
        List<Map<String, Object>> list = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            JSONObject resultObject = null;
            //拼接URL发送对应的请求
            StringBuffer url = new StringBuffer();
            url.append("https://api.vvhan.com/api/rand.music?type=json&sort=热歌榜");
            //获取接口的返回值
            String body = HttpUtils.sendGet(url.toString());
            resultObject = JSONObject.parseObject(body);
            JSONObject info = JSONObject.parseObject(resultObject.get("info").toString());
            HashMap<String, Object> map = new HashMap<String, Object>();
            map.put("id", info.get("id").toString());
            map.put("name", info.get("name"));
            map.put("artistsName", info.get("auther"));
            map.put("cover", info.get("picUrl"));
            map.put("url", info.get("mp3url"));
            map.put("lyric", this.getMusicLyricById(info.get("id").toString()) != null ? this.getMusicLyricById(info.get("id").toString()) : null);
            list.add(map);
            log.info("调用成功" + i + "次");
        }
        return list;
    }

    /*
     * @version V1.0
     * Title: getMusicLyricById
     * @author LiuYanQiang
     * @description 获取歌词信息
     * @createTime  2021/11/16 19:23
     * @param [Id——音乐Id]
     * @return java.lang.String*/
    @Override
    public String getMusicLyricById(String Id) {
        try {
            JSONObject resultObject = null;
            //拼接URL发送对应的请求
            StringBuffer url = new StringBuffer();
            url.append("https://music.163.com/api/song/media?id=" + Id);
            //获取接口的返回值
            String body = HttpUtils.sendGet(url.toString());
            resultObject = JSONObject.parseObject(body);
            if (resultObject.get("lyric").toString() != null) {
                return resultObject.get("lyric").toString();
            } else {
                return null;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

总结

到此这篇关于vue仿网易云音乐播放器界面简单实现的文章就介绍到这了,更多相关vue网易云音乐播放器界面内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • vue模仿网易云音乐的单页面应用

    说明 一直想做一个基于VUE的项目,但是因为项目往往要涉及到后端的知识(不会后端真的苦),所以就没有一直真正的动手去做一个项目. 直到发现GitHub上有网易云音乐的api NeteaseCloudMusicApi,才开始动手去做. 仅仅完成了首页,登入,歌单,歌曲列表页. 项目地址 https://github.com/qp97vi/music 项目成功运行还要把后端api在本地运行 前端技术栈 vue2+vuex+vue-router+axios+mint-ui+webpack 遇到的问题

  • Vuejs仿网易云音乐实现听歌及搜索功能

    前言 前端时间学了vue,一开始看了vue1.0,后来实在觉得技术总得实践,就直接上手vue2.0.然后花了将近一周时间做了一个网易云音乐的小项目.一开始觉得项目比较小,没必要用vuex所以就没有使用,但是后来发现数据流传输有点麻烦,后续会使用vuex. 技术栈 vue+vue-router(核心框架) better-scroll(使移动端滑动体验更加流畅) vue-lazyload(用户图片懒加载) nprogress(用于加载过渡) axios(请求) 功能分析与设计 首先我先参考了现有的一

  • vue实现的网易云音乐在线播放和下载功能案例

    本文实例讲述了vue实现的网易云音乐在线播放和下载功能.分享给大家供大家参考,具体如下: 效果如图: 完整代码: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"

  • mpvue网易云短信接口实现小程序短信登录的示例代码

    上一篇简单介绍了mpvue实现快递单号查询,慢慢发现mpvue真的和vue很像,但它有几乎十分的吻合小程序的语法规范,刚开始用起来会觉得特点的爽,但涉及到细节却是有很多采坑的地方.今天利用网上的网易云接口,再结合mpvue简单写一写小程序短信验证登录. 简单封装的一个网络请求文件,网易云接口网上大佬们GitHub上还是比较的多而且开源 const baseURL = "https://*****:1717"; //基路径 exports.http = function({url,met

  • vue仿网易云音乐播放器界面的简单实现过程

    由于工作项目的需要,需要使用到歌曲播放,参考多方资料,写了一个仿网易云音乐播放界面,能完整的实现音乐播放功能. 前端简单的使用vue组件和audio标签实现了播放器界面,后端则是调用网易云的API获取对应的歌曲信息.  废话不多说上代码 歌曲播放界面(musicPlay.vue) <template> <div class="main-page"> <audio :src="songInfo.url" id="music&qu

  • Android仿网易云音乐播放界面

    现在很多的播放器的播放界面都是采用光盘的转动,下面是我仿造网易的播放界面.先上两张图: 第一张为播放前的界面,第二张为点击播放按钮的图片.布局文件如下: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent&quo

  • 漂亮的Android音乐歌词控件 仿网易云音乐滑动效果

    前言: 项目有个音乐播发器功能,实现音乐在线播放,同时需要带有歌词显示功能.网上也找过,在github找到勉强能用的控件,只是效果还是差强人意,不是特别好.于是趁有空的时间,参考了网上的部分demo,自己也写了个歌词控件. 只要demo可以拉到最底部. 一.歌词控件效果. 目前的歌词控件效果如下: 主要效果有以下: 1.实现自动滑动切换到下一句. 2.实现滑动歌词切换播放时间. 3.实现拖动歌词时仿网易云音乐显示时间线,将要选择的歌词颜色变化. 4.音乐进度跳转时,歌词跳转可以滑动切换. 二.歌

  • Android项目实战教程之高仿网易云音乐启动页实例代码

    前言 本文主要给大家介绍了关于Android高仿网易云音乐启动页的相关内容,这一节我们来讲解启动界面,效果如下: 首次创建一个SplashActivity用来做启动界面,因为创建完项目默认是MainActivity做主界面,所以需要去掉,将启动配置到同时去掉SplashActivity,并且去掉SplashActivity的标题栏,同时还要设置为全屏. Activity启动配置 在清单文件将启动配置剪贴到SplashActivity: <activity android:name=".ac

  • Android控件RecyclerView实现混排效果仿网易云音乐

    前言 最近在使用网易云音乐的时候,看到如下图的排版效果图,自己也想实现一个 这里采用网上用法最多的方式,而且是比较简单的方式实现的,想要做项目的同学也可以快速入手搞定首页界面,可以在最快的时间内模仿出来,且效果达到90%以上的相似 效果演示 至于图片的加载你们可以根据网上的Api获取相应的图片加载到对应的位置,这里只是采用本地图片来演示 实现分析 这里是采用RecyclerView的GridLayoutManager的一个SpanSize这么一个东西,从下图很容易知道其意思 项目结构 项目结构可

  • vue实现网易云音乐纯界面

    目录 项目简介 使用姿势 项目结构 界面截图 登录页 发现 播客 我的 关注 搜索 项目简介 使用 Vue Cli + Vue3 + Vant3 编写 [Github地址:github.com/cloudmoonoc…] [网易云音乐接口地址:neteasecloudmusicapi.vercel.app] 使用姿势 npm install npm run serve 项目结构 存在部分问题,在README中 ├─public └─src ├─Api (接口[未做]) │ ├─assets │

  • React模仿网易云音乐实现一个音乐项目详解流程

    目录 一.项目功能说明 二.最终效果 三.文件目录结构说明 四.项目技术栈 五.核心技术 六.遇到的问题 七.github链接 一.项目功能说明 暂停.播放歌曲 切换上一首.下一首歌曲 拖动进度条改变播放进度 随机播放.循环播放.单曲循环 实时展示歌词 切换不同分类的歌单.歌手.电台 实现推荐.排行榜.歌单.主播电台.歌手.新碟上架板块的展示 二.最终效果 首页: 排行榜: 歌单: 主播电台: 歌手: 新碟上架: 三.文件目录结构说明 assets:存放共用的css.font图标.image c

随机推荐