Preface: I learn VUEJS for a period of time, but I have not made a thing. I always like to use netease cloud music APP, so I made this app.
Technology stack
-
Vue (Vue vuE-Router Vuex)
-
axios
-
Muse-ui (a Material Design Style UI framework based on Ve2. X)
Analysis of functions and ideas
I studied Html5 Audio and wrote some examples when I was learning JS. At that time, the functions were not very comprehensive. Before writing this application, I took a good look at the audio tag in current HTML5 and found that a garden friend summed it up well (here). Therefore, the most basic functions of netease Cloud music will be realized first, namely the song list part (which is also the reason why I like netease Cloud Music), and then the music will be played and paused. List function.
The background
.net is used as the background to provide system request API(source code), the principle is very simple is to use.NET disguised as a client to access netease cloud music API and then return the JSON data forward out. At the same time, the server performs cross-domain processing.
Core code:
/// <summary>
///Request netease Cloud Music interface
/// </summary>
/// <typeparam name="T">The type of interface to request</typeparam>
/// <param name="config">Object of the type of interface to request</param>
/// <returns>Request result (JSON)</returns>
public static string Request<T>(T config) where T : RequestData, new()
{
/ / request URL
string requestURL = config.Url;
// Convert the packet object to a QueryString
string @params = config.FormData.ParseQueryString();
bool isPost = config.Method.Equals("post", StringComparison.CurrentCultureIgnoreCase);
if(! isPost) {// Splice request URL in get mode
string sep = requestURL.Contains('? ')?"&" : "?";
requestURL += sep + @params;
}
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(requestURL);
req.Accept = "* / *";
req.Headers.Add("Accept-Language"."zh-CN,zh; Q = 0.8, gl; Q = 0.6, useful - TW; Q = 0.4");
// If the server is enabled with GZIP, then the following must be decompressed, otherwise the garbled characters will continue.
/ / see: http://www.crifan.com/set_accept_encoding_header_to_gzip_deflate_return_messy_code/
req.Headers.Add("Accept-Encoding"."gzip,deflate,sdch");
req.ContentType = "application/x-www-form-urlencoded";
req.KeepAlive = true;
req.Host = "music.163.com";
req.Referer = "http://music.163.com/search/";
req.UserAgent = "Mozilla / 5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537";
/ / set cookies
req.Headers["Cookie"] = "Appver = 1.5.2";
req.Method = config.Method;
req.AutomaticDecompression = DecompressionMethods.GZip;
if (isPost)
{
// Write the POST request package
byte[] formData = Encoding.UTF8.GetBytes(@params);
/ / set the HTTP request header reference: https://github.com/darknessomi/musicbox/blob/master/NEMbox/api.py
req.GetRequestStream().Write(formData, 0, formData.Length);
}
// Send the HTTP request and read the response
return new StreamReader(req.GetResponse().GetResponseStream(), Encoding.GetEncoding("UTF-8")).ReadToEnd();
}Copy the code
Vuejs part
The project structure
├ ─ ─index.html ├ ─ ─ main. Js ├ ─ ─ API │ └ ─ ─...Extract THE API request├── ├─ Bass exercises. │ ├─ ├─ bass exercises. └ ─ ─ store │ └ ─ ─index.js # VuEX part of the whole project└── garbage │ ├ ─ garbage# Routing of the entire project└ ─ ─ utils# Some utility class modules│ └ ─ ─ views# Some Route-Views in the projectCopy the code
Before we talk about the route of the project, let’s take a look at a rendering
For the whole project: the view difference is the navigation at the top, and whether the bar below comes out depends on whether there are songs in the current system list, and if there are, they will appear.
Router.js core
const router = new VueRouter({
mode: 'history',
routes: [{
path: '/index',
component: require('.. /views/index'),
children: [
{
path: 'rage',
component: require('.. /views/rage')
},
{
path: 'songList',
component: require('.. /views/songList')
},
{
path: 'leaderBoard',
component: require('.. /views/leaderBoard')
},
{
path: 'hotSinger',
component: require('.. /views/hotSinger')
}
]
}, {
name: 'playerDetail',
path: '/playerDetail/:id',
component: require('.. /views/playerDetail')
}, {
path: '/playListDetail/:id',
name: 'playListDetail',
component: require('.. /views/playListDetail')
}, {
path: The '*', redirect: '/index/rage'}].// Scroll to the top of each page and change the mode to mode: history
scrollBehavior (to, from, savedPosition) {
if (savedPosition) {
return savedPosition
} else {
return { x: 0, y: 0}}}})Copy the code
Vuex part
This part, mainly songs, because different pages have different use of song information, put this part of data into VUEX for unified data processing! sotre/index.js
const store = new Vuex.Store({
state: {
audio: {
'id': 0.'name': 'Song Title'.'singer': 'singer'.'albumPic': '/static/player-bar.png'.'location': ' '.'album': ' '
},
lyric: 'Loading. ',
currentIndex: 0.// The current position of the song
playing: false.// Whether it is playing
loading: false.// Whether the file is being loaded
showDetail: false,
songList: [], // Playlist
currentTime: 0,
tmpCurrentTime: 0,
durationTime: 0,
bufferedTime: 0,
change: false // Determine whether it is the changed time or the playback time
},
getters: {
audio: state => state.audio,
playing: state => state.playing,
loading: state => state.loading,
showDetail: state => state.showDetail,
durationTime: state => state.durationTime,
currentIndex: state => state.currentIndex,
bufferedTime: state => state.bufferedTime,
tmpCurrentTime: state => state.tmpCurrentTime,
songList: state => state.songList,
change: state => state.change,
currentTime: state => state.currentTime,
prCurrentTime: state => {
return state.currentTime / state.durationTime * 100
},
prBufferedTime: state => {
return state.bufferedTime / state.durationTime * 100
}
},
mutations: {
play (state) {
state.playing = true
},
pause (state) {
state.playing = false}, toggleDetail (state) { state.showDetail = ! state.showDetail }, setAudio (state) { state.audio = state.songList[state.currentIndex -1]
},
setAudioIndex (state, index) {
state.audio = state.songList[index]
state.currentIndex = index + 1
},
removeAudio (state, index) {
state.songList.splice(index, 1)
state.audio = state.songList[index - 1]
state.currentIndex = state.currentIndex - 1
if (state.songList.length === 0) {
state.audio = {
'id': 0.'name': 'Song Title'.'singer': 'singer'.'albumPic': '/static/player-bar.png'.'location': ' '.'album': ' '
}
state.playing = false
}
},
setChange (state, flag) {
state.change = flag
},
setLocation (state, location) {
state.audio.location = location
},
updateCurrentTime (state, time) {
state.currentTime = time
},
updateDurationTime (state, time) {
state.durationTime = time
},
updateBufferedTime (state, time) {
state.bufferedTime = time
},
changeTime (state, time) {
state.tmpCurrentTime = time
},
openLoading (state) {
state.loading = true
},
closeLoading (state) {
state.loading = false
},
resetAudio (state) {
state.currentTime = 0
},
playNext (state) { // Play the next song
state.currentIndex++
if (state.currentIndex > state.songList.length) {
state.currentIndex = 1
}
state.audio = state.songList[state.currentIndex - 1]
},
playPrev (state) { // Play the previous song
state.currentIndex--
if (state.currentIndex < 1) {
state.currentIndex = state.songList.length
}
state.audio = state.songList[state.currentIndex - 1]
},
addToList (state, item) {
var flag = false
state.songList.forEach(function (element, index) { // Detect song repetition
if (element.id === item.id) {
flag = true
state.currentIndex = index + 1}})if(! flag) { state.songList.push(item) state.currentIndex = state.songList.length } }, setLrc (state, lrc) { state.lyric = lrc } },// Asynchronous data manipulation
actions: {
getSong ({commit, state}, id) {
commit('openLoading')
Axios.get(api.getSong(id)).then(res => {
// Unified data model, convenient background interface change
var url = res.data.data[0].url
commit('setAudio')
commit('setLocation', url)
})
},
getLrc ({commit, state}, id) {
commit('setLrc'.'[TXT](loading... ')
Axios.get(api.getLrc(id)).then(res => {
// 1, check if there are lyrics
if (res.data.nolyric) {
commit('setLrc'.'[TXT](⊙0⊙))}else {
console.log(res.data.lrc.lyric)
commit('setLrc', res.data.lrc.lyric)
}
})
}
}
})Copy the code
Finally, click on the project screenshot
Github project address: github.com/javaSwing/N…
Currently, I have only completed the app playlist, which is also the core part. This project will be updated all the time! Give a star if you feel good