基于Vue和Spring Boot的框架在线音乐平台的设计与实现
前端实现过程记录
项目初始化
- 创建项目
vue create cloud-music
- elementUI的安装与引入
安装:npm i element-ui -S
引入:先使用完整引用,项目开发完成后使用按需引入,在main.js文件中:
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI)
- 音乐数据
NeteaseCloudMusicApi
git clone https://github.com/Binaryify/NeteaseCloudMusicApi.git
npm install
node app.js
- 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:''
},
- vue-video-player的安装和使用
安装:npm install vue-video-player -S
axios封装
- 安装axios
npm i axios -S
- 封装api接口
const musicApi={
baseUrl:'http://localhost:3000',
}
export default musicApi
- 封装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
歌单模块
数据处理
- 接口
songListCategories:'/playlist/catlist',//歌单分类
songLists:'/top/playlist',//歌单列表
songList:'/playlist/track/all',//歌单所有歌曲
songListDetail:'/playlist/detail',//歌单详情
- 数据请求
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
}
})
}
- 数据访问
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
}
})
}
歌曲播放模块
数据处理
- 接口
songUrl:'/song/url', //歌曲链接
songDetail:'/song/detail', //歌曲详情
songLyric:'/lyric',//歌词
- 数据请求
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)])
}
- 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);
}
- 视频播放器组件
模块功能
- 接口
- 数据请求
- 数据访问