前端Java音乐_用VUEJS做一个网易云音乐

本文介绍了一个使用VueJS、Vuex、axios和Muse-UI创建的网易云音乐前端应用。通过.net作为后台,模拟客户端访问网易云音乐API并转发JSON数据。项目实现了基本的音乐播放功能,包括播放列表、上一曲、下一曲、播放暂停等。VueRouter用于路由管理,Vuex用于状态管理。
摘要由CSDN通过智能技术生成

前言:自己学习VUEJS也一段时间,但一直没有做出来一东西。我自己一直喜欢用网易云音乐app,于是乎就做了这个app。

技术栈

vue全家桶 (vue vue-router vuex)

axios

Muse-UI(一个基于Vue2.x的material design 风格UI框架)

功能与思路分析

我之前学习JS的时候对Html5 audio研究过,也写过一些例子,那时的功能并不是很全面。在写这个程序之前,我好好的查阅了当前的HTML5中的audio标签,发现园子上一位园友总结的很不错(这里)。于是就先把网易云音乐最基本的功能实现,歌单部分(这也是我喜欢网易云音乐的原因这一),然后实现音乐的上一曲、下一曲,播放、暂停。列表功能。

后台

后台采用.net做为后台提供系统请求所用的API(源码),原理很简单就是用.net伪装成一个客户端去访问网易云音乐的API然后,把返回的json数据转发出来。同时服务端做下跨域处理。

核心代码:

///

/// 请求网易云音乐接口

///

/// 要请求的接口类型

/// 要请求的接口类型的对象

/// 请求结果(JSON)

public static string Request(T config) where T : RequestData, new()

{

// 请求URL

string requestURL = config.Url;

// 将数据包对象转换成QueryString形式的字符串

string @params = config.FormData.ParseQueryString();

bool isPost = config.Method.Equals("post", StringComparison.CurrentCultureIgnoreCase);

if (!isPost)

{

// get方式 拼接请求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");

// 如果服务端启用了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";

// 设置cookies

req.Headers["Cookie"] = "appver=1.5.2";

req.Method = config.Method;

req.AutomaticDecompression = DecompressionMethods.GZip;

if (isPost)

{

// 写入post请求包

byte[] formData = Encoding.UTF8.GetBytes(@params);

// 设置HTTP请求头 参考:https://github.com/darknessomi/musicbox/blob/master/NEMbox/api.py

req.GetRequestStream().Write(formData, 0, formData.Length);

}

// 发送http请求 并读取响应内容返回

return new StreamReader(req.GetResponse().GetResponseStream(), Encoding.GetEncoding("UTF-8")).ReadToEnd();

}

vuejs部分

项目结构

├── index.html

├── main.js

├── api

│ └── ... # 抽取出API请求

├── components

│ ├── playBar.vue

│ └── ...

└── store

│ └── index.js # 整个项目的vuex部分

└── router

│ └── router.js # 整个项目的路由

└── utils # 一些工具类模块

└── views # 项目中的一些route-view

说项目的路由之前,先来看一张效果图

b6ffde440b610b89b94373da08062868.gif

对于整个项目来说:视图区别在于顶部导航,下面的bar的是否出来取决于,当前系统列表中是否有歌曲,如果有就会出现。

e2cf19991408d122033ec0e179adf6dd.png

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'

}],

// 让每个页面都滚动到顶部,改变模式为mode: history

scrollBehavior (to, from, savedPosition) {

if (savedPosition) {

return savedPosition

} else {

return { x: 0, y: 0 }

}

}

})

vuex部分

这部分,主要是歌曲这一块,因为不同的页面有不同的使用到了歌曲信息,把把这部分数据放到vuex中做统一的数据处理!

sotre/index.js

const store = new Vuex.Store({

state: {

audio: {

'id': 0,

'name': '歌曲名称',

'singer': '演唱者',

'albumPic': '/static/player-bar.png',

'location': '',

'album': ''

},

lyric: '正在加载中。。',

currentIndex: 0, // 当前播放的歌曲位置

playing: false, // 是否正在播放

loading: false, // 是否正在加载中

showDetail: false,

songList: [], // 播放列表

currentTime: 0,

tmpCurrentTime: 0,

durationTime: 0,

bufferedTime: 0,

change: false // 判断是更改的时间还是播放的时间

},

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) { // 检测歌曲重复

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

}

},

// 异步的数据操作

actions: {

getSong ({commit, state}, id) {

commit('openLoading')

Axios.get(api.getSong(id)).then(res => {

// 统一数据模型,方便后台接口的改变

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⊙) 暂无歌词')

} else {

console.log(res.data.lrc.lyric)

commit('setLrc', res.data.lrc.lyric)

}

})

}

}

})

最后上点项目截图

bc6f835d20115e77c3760d28ce70520a.png

760d1604d4df546705209a06d64fbbfc.gif

目前只完成app歌单部分,也是最核心的部分。这个项目会一直更新!如果觉的不错就给个star吧

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值