基于Vue和Spring Boot的框架在线音乐平台的设计与实现

基于Vue和Spring Boot的框架在线音乐平台的设计与实现

前端实现过程记录


项目初始化

  1. 创建项目
    vue create cloud-music
  2. elementUI的安装与引入
    安装:npm i element-ui -S
    引入:先使用完整引用,项目开发完成后使用按需引入,在main.js文件中:
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI)
  1. 音乐数据
    NeteaseCloudMusicApi
git clone https://github.com/Binaryify/NeteaseCloudMusicApi.git
npm install
node app.js
  1. vue-aplayer的安装和使用
    安装:npm i vue-aplayer -S
    使用:创建播放器组件,导入import Aplayer from 'vue-aplayer'
<aplayer v-if="song.src"
           autoplay
           :music="song"
           :list="playList"
           showLrc
           repeat="list"
           listFolded
  />
song: {
      src: '',
      title:'',
      artist:'',
      pic:'',
      lrc:''
    },
  1. vue-video-player的安装和使用
    安装:npm install vue-video-player -S

axios封装

  1. 安装axios
    npm i axios -S
  2. 封装api接口
const musicApi={
    baseUrl:'http://localhost:3000',
}
export default musicApi
  1. 封装axios
import axios from "axios";
import api from "./api";

const request = axios.create({
    baseURL:api.baseUrl,
    timeout: 5000
})
request.interceptors.request.use(config => {
        return config
    }, error => {
        return Promise.reject(error)
    }
)
request.interceptors.response.use(res=>{
    return res.data
},error => {
    return Promise.reject(error)
})
export default request

歌单模块

数据处理

  1. 接口
    songListCategories:'/playlist/catlist',//歌单分类
    songLists:'/top/playlist',//歌单列表
    songList:'/playlist/track/all',//歌单所有歌曲
    songListDetail:'/playlist/detail',//歌单详情
  1. 数据请求
export function getSongListCategories() {
    return request({
        url: musicApi.baseUrl + musicApi.songListCategories
    })
}
export function getSongLists(cat, limit, offset) {
    return request({
        url: musicApi.baseUrl + musicApi.songLists,
        params: {
            cat,
            limit,
            offset
        }
    })
}
export function getSongList(id, limit, offset) {
    return request({
        url: musicApi.baseUrl + musicApi.songList,
        params: {
            id,
            limit,
            offset
        }
    })
}
export function getSongListDetail(id){
    return request({
        url:musicApi.baseUrl+musicApi.songListDetail,
        params:{
            id
        }
    })
}
  1. 数据访问
    getSongListCategories() {
      getSongListCategories().then(res => {
        this.categories = res.categories
        for (let item of res.sub) {
          let sub={
            name:item.name,
            category:item.category,
            activity:item.activity
          }
          this.sub.push(sub)
        }
      })
    },
    getSongLists(cat,limit,offset){
      getSongLists(cat,limit,offset).then(res=>{
        for(let item of res.playlists){
          let songList={
            id:item.id,
            name: item.name,
            coverImgUrl:item.coverImgUrl,
            playCount:item.playCount,
            creator:item.creator.nickname,
          }
          this.songLists.push(songList)
        }
      })
    },
    getSongListDetail(id){
      getSongListDetail(id).then(res=>{
        let songListInfo=res.playlist;
        let creatorInfo=res.playlist.creator;
        this.songListDetail={
          //歌单名
          name:songListInfo.name,
          //标签
          tags:songListInfo.tags,
          //介绍
          description:songListInfo.description,
          //作者
          nickname:creatorInfo.nickname,
          avatarUrl:creatorInfo.avatarUrl,
          //创建时间
          createTime:songListInfo.createTime,
          //评论量
          commentCount:songListInfo.commentCount,
          //封面
          coverImgUrl:songListInfo.coverImgUrl
        }
      })
    },
    getSongList(id,limit,offset){
      getSongList(id,limit,offset).then(res=>{
        for(let item of res.songs){
          let song={
            id:item.id,
            name:item.name,
            arId:item.ar[0].id,
            arName:item.ar[0].name,
            alId:item.al.id,
            alName:item.al.name,
            alPicUrl:item.al.picUrl
          }
          this.songs.push(song)

        }
      })
    }

逻辑处理
业务流程:
1、用户进入歌单页,展示所有歌单分类
2、点击分类显示相应的歌单列表
3、点击歌单进入歌单详情页、展示歌单的信息和包含歌曲列表

    categoryClick(cat) {
      this.songLists = [];
      this.getSongLists(cat)
    },
    songListClick(id) {
      this.$router.push({
        name: 'SongListDetail',
        params: {
          id
        }
      })
    }

歌曲播放模块

数据处理

  1. 接口
    songUrl:'/song/url', //歌曲链接
    songDetail:'/song/detail', //歌曲详情
    songLyric:'/lyric',//歌词
  1. 数据请求
export function getSongUrl(id){
    return request({
        url:musicApi.baseUrl+musicApi.songUrl,
        params:{
            id
        }
    })
}
export function getSongDetail(ids){
    return request({
        url:musicApi.baseUrl+musicApi.songDetail,
        params:{
            ids
        }
    })
}
export function getSongLyric(id){
    return request({
        url:musicApi.baseUrl+musicApi.songLyric,
        params:{
            id
        }
    })
}
//并发异步请求
export function getSong(id){
    return axios.all([getSongUrl(id),getSongDetail(id),getSongLyric(id)])
}
  1. Vuex保存音乐播放器状态
import Vue from 'vue'
import Vuex from 'vuex'
import {getSong} from "@/network/music/songlist/songlist";

Vue.use(Vuex)

export default new Vuex.Store({
    state: {
        songId: 0,
        song: {
            src: '',
            title: '',
            artist: '',
            pic: '',
            lrc: ''
        },
        playList: []
    },
    mutations: {
        setSongId(state, id) {
            return state.songId = id;
        },
        getSong(state, song) {
            return state.song = song;
        },
        getPlayList(state, song) {
            if (state.playList.length === 0) {
                return state.playList.push(song);
            } else {
                let addition = true;
                for (let item of state.playList) {
                    if (item.title === song.title) {
                        addition = false
                        break;
                    }
                }
                if (addition) {
                    return state.playList.push(song);
                }
            }
        }
    },
    actions: {
        getSong(context, id) {
            getSong(id).then(res => {
                let song = {
                    src: res[0].data[0].url,
                    title: res[1].songs[0].name,
                    artist: res[1].songs[0].ar[0].name,
                    pic: res[1].songs[0].al.picUrl,
                    lrc: res[2].lrc.lyric
                }
                context.commit('getSong', song);
                context.commit('getPlayList', song);
            })
        },
    },
    modules: {}
})

4.音乐播放器组件

export default {
  name: "MusicPlayer",
  components: {
    Aplayer
  },
  computed:{
    songID(){
      return this.$store.state.songId
    },
    song(){
      return this.$store.state.song
    },
    playList(){
      return this.$store.state.playList
    }
  },
  watch: {
    songID() {
      this.$store.state.song = {
        src: '',
        title: '',
        artist: '',
        pic: '',
        lrc: ''
      };
      this.$store.dispatch('getSong',this.songID);
    }
  }
}
<template>
  <div id="player">
    <aplayer v-if="song.src"
             autoplay
             :music="song"
             :list="playList"
             showLrc
             repeat="list"
             listFolded
             theme="#861AFF"
    />
  </div>
</template>

逻辑处理
用户点击播放按钮播放歌曲

   songClick(id) {
      this.$store.commit('setSongId',id);
    }
  1. 视频播放器组件

模块功能

  1. 接口

  1. 数据请求

  1. 数据访问

上一篇:scrapy之请求传参、图片爬取与中间件


下一篇:C#中的集合