摘要:我自己一直喜歡用網(wǎng)易云音樂,于是乎就做了這個(gè)。后臺(tái)后臺(tái)采用做為后臺(tái)提供系統(tǒng)請(qǐng)求所用的源碼,原理很簡(jiǎn)單就是用偽裝成一個(gè)客戶端去訪問網(wǎng)易云音樂的然后,把返回的數(shù)據(jù)轉(zhuǎn)發(fā)出來(lái)。
技術(shù)棧前言:自己學(xué)習(xí)VUEJS也一段時(shí)間,但一直沒有做出來(lái)一東西。我自己一直喜歡用網(wǎng)易云音樂app,于是乎就做了這個(gè)app。
vue全家桶 (vue vue-router vuex)
axios
Muse-UI(一個(gè)基于Vue2.x的material design 風(fēng)格UI框架)
功能與思路分析我之前學(xué)習(xí)JS的時(shí)候?qū)tml5 audio研究過(guò),也寫過(guò)一些例子,那時(shí)的功能并不是很全面。在寫這個(gè)程序之前,我好好的查閱了當(dāng)前的HTML5中的audio標(biāo)簽,發(fā)現(xiàn)園子上一位園友總結(jié)的很不錯(cuò)(這里)。于是就先把網(wǎng)易云音樂最基本的功能實(shí)現(xiàn),歌單部分(這也是我喜歡網(wǎng)易云音樂的原因這一),然后實(shí)現(xiàn)音樂的上一曲、下一曲,播放、暫停。列表功能。
后臺(tái)后臺(tái)采用.net做為后臺(tái)提供系統(tǒng)請(qǐng)求所用的API(源碼),原理很簡(jiǎn)單就是用.net偽裝成一個(gè)客戶端去訪問網(wǎng)易云音樂的API然后,把返回的json數(shù)據(jù)轉(zhuǎn)發(fā)出來(lái)。同時(shí)服務(wù)端做下跨域處理。
核心代碼:
///vuejs部分/// 請(qǐng)求網(wǎng)易云音樂接口 /// ///要請(qǐng)求的接口類型 /// 要請(qǐng)求的接口類型的對(duì)象 ///請(qǐng)求結(jié)果(JSON) public static string Request(T config) where T : RequestData, new() { // 請(qǐng)求URL string requestURL = config.Url; // 將數(shù)據(jù)包對(duì)象轉(zhuǎn)換成QueryString形式的字符串 string @params = config.FormData.ParseQueryString(); bool isPost = config.Method.Equals("post", StringComparison.CurrentCultureIgnoreCase); if (!isPost) { // get方式 拼接請(qǐng)求url 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,zh-TW;q=0.4"); // 如果服務(wù)端啟用了GZIP,那么下面必須解壓,否則一直亂碼。 // 參見: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"; // 設(shè)置cookies req.Headers["Cookie"] = "appver=1.5.2"; req.Method = config.Method; req.AutomaticDecompression = DecompressionMethods.GZip; if (isPost) { // 寫入post請(qǐng)求包 byte[] formData = Encoding.UTF8.GetBytes(@params); // 設(shè)置HTTP請(qǐng)求頭 參考:https://github.com/darknessomi/musicbox/blob/master/NEMbox/api.py req.GetRequestStream().Write(formData, 0, formData.Length); } // 發(fā)送http請(qǐng)求 并讀取響應(yīng)內(nèi)容返回 return new StreamReader(req.GetResponse().GetResponseStream(), Encoding.GetEncoding("UTF-8")).ReadToEnd(); }
項(xiàng)目結(jié)構(gòu)
├── index.html ├── main.js ├── api │ └── ... # 抽取出API請(qǐng)求 ├── components │ ├── playBar.vue │ └── ... └── store │ └── index.js # 整個(gè)項(xiàng)目的vuex部分 └── router │ └── router.js # 整個(gè)項(xiàng)目的路由 └── utils # 一些工具類模塊 │ └── views # 項(xiàng)目中的一些route-view
說(shuō)項(xiàng)目的路由之前,先來(lái)看一張效果圖
對(duì)于整個(gè)項(xiàng)目來(lái)說(shuō):視圖區(qū)別在于頂部導(dǎo)航,下面的bar的是否出來(lái)取決于,當(dāng)前系統(tǒng)列表中是否有歌曲,如果有就會(huì)出現(xiàn)。
router.js核心部分
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: "*", redirect: "/index/rage" }], // 讓每個(gè)頁(yè)面都滾動(dòng)到頂部,改變模式為mode: history scrollBehavior (to, from, savedPosition) { if (savedPosition) { return savedPosition } else { return { x: 0, y: 0 } } } })
vuex部分
這部分,主要是歌曲這一塊,因?yàn)椴煌捻?yè)面有不同的使用到了歌曲信息,把把這部分?jǐn)?shù)據(jù)放到vuex中做統(tǒng)一的數(shù)據(jù)處理!
sotre/index.js
const store = new Vuex.Store({ state: { audio: { "id": 0, "name": "歌曲名稱", "singer": "演唱者", "albumPic": "/static/player-bar.png", "location": "", "album": "" }, lyric: "正在加載中。。", currentIndex: 0, // 當(dāng)前播放的歌曲位置 playing: false, // 是否正在播放 loading: false, // 是否正在加載中 showDetail: false, songList: [], // 播放列表 currentTime: 0, tmpCurrentTime: 0, durationTime: 0, bufferedTime: 0, change: false // 判斷是更改的時(shí)間還是播放的時(shí)間 }, 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": "歌曲名稱", "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) { // 播放下一曲 state.currentIndex++ if (state.currentIndex > state.songList.length) { state.currentIndex = 1 } state.audio = state.songList[state.currentIndex - 1] }, playPrev (state) { // 播放上一曲 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) { // 檢測(cè)歌曲重復(fù) 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 } }, // 異步的數(shù)據(jù)操作 actions: { getSong ({commit, state}, id) { commit("openLoading") Axios.get(api.getSong(id)).then(res => { // 統(tǒng)一數(shù)據(jù)模型,方便后臺(tái)接口的改變 var url = res.data.data[0].url commit("setAudio") commit("setLocation", url) }) }, getLrc ({commit, state}, id) { commit("setLrc", "[txt](加載中。。。") Axios.get(api.getLrc(id)).then(res => { // 1、先判斷是否有歌詞 if (res.data.nolyric) { commit("setLrc", "[txt](⊙0⊙) 暫無(wú)歌詞") } else { console.log(res.data.lrc.lyric) commit("setLrc", res.data.lrc.lyric) } }) } } })
最后上點(diǎn)項(xiàng)目截圖
github項(xiàng)目地址:https://github.com/javaSwing/NeteaseCloudWebApp
目前只完成app歌單部分,也是最核心的部分。這個(gè)項(xiàng)目會(huì)一直更新!如果覺的不錯(cuò)就給個(gè)star吧
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/88138.html
摘要:高仿低配網(wǎng)頁(yè)版網(wǎng)易云音樂播放器前言沒有使用任何框架,只是想用最簡(jiǎn)單純的代碼實(shí)現(xiàn)下前臺(tái)后臺(tái)是參考網(wǎng)上的例子寫的,代碼是在的基礎(chǔ)上重新寫的還有她的姊妹篇網(wǎng)易云音樂移動(dòng)端,請(qǐng)查看這里寫在前頭的話鄙人野生前端一只,專業(yè),自學(xué)前端已經(jīng)一年多了 HTML+CSS+JAVASCRIPT 高仿低配網(wǎng)頁(yè)版網(wǎng)易云音樂播放器 showImg(https://segmentfault.com/img/remo...
摘要:高仿低配網(wǎng)頁(yè)版網(wǎng)易云音樂播放器前言沒有使用任何框架,只是想用最簡(jiǎn)單純的代碼實(shí)現(xiàn)下前臺(tái)后臺(tái)是參考網(wǎng)上的例子寫的,代碼是在的基礎(chǔ)上重新寫的還有她的姊妹篇網(wǎng)易云音樂移動(dòng)端,請(qǐng)查看這里寫在前頭的話鄙人野生前端一只,專業(yè),自學(xué)前端已經(jīng)一年多了 HTML+CSS+JAVASCRIPT 高仿低配網(wǎng)頁(yè)版網(wǎng)易云音樂播放器 showImg(https://segmentfault.com/img/remo...
摘要:如何能低成本地快速獲取大量目標(biāo)用戶,而不是與競(jìng)爭(zhēng)對(duì)手持久戰(zhàn)這在如今的互聯(lián)網(wǎng)上并不常見。產(chǎn)品經(jīng)理需要尋找那些對(duì)產(chǎn)品價(jià)值最大的需求,而低成本地快速獲取大量目標(biāo)用戶,就是重要的思考路徑之一。 此文已由作者王詩(shī)沐授權(quán)網(wǎng)易云社區(qū)發(fā)布。 歡迎訪問網(wǎng)易云社區(qū),了解更多網(wǎng)易技術(shù)產(chǎn)品運(yùn)營(yíng)經(jīng)驗(yàn)。 如何能低成本地快速獲取大量目標(biāo)用戶,而不是與競(jìng)爭(zhēng)對(duì)手持久戰(zhàn)? 這在如今的互聯(lián)網(wǎng)上并不常見。現(xiàn)在,大部分行業(yè)都已...
閱讀 1019·2022-07-19 10:19
閱讀 1794·2021-09-02 15:15
閱讀 1007·2019-08-30 15:53
閱讀 2653·2019-08-30 13:45
閱讀 2652·2019-08-26 13:57
閱讀 1983·2019-08-26 12:13
閱讀 1006·2019-08-26 10:55
閱讀 545·2019-08-26 10:46