项目初始化
vue create cloud-music
npm i element-ui -S
import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' Vue.use(ElementUI)
git clone https://github.com/Binaryify/NeteaseCloudMusicApi.git npm install node app.js
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:'' },
npm install vue-video-player -S
axios封装
npm i axios -S
const musicApi={ baseUrl:'http://localhost:3000', } export default musicApi
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)]) }
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); }
模块功能