技术栈
功能与思路分析我之前学习JS的时候对Html5 audio研究过,也写过一些例子,那时的功能并不是很全面。在写这个程序之前,我好好的查阅了当前的HTML5中的audio标签,发现园子上一位园友总结的很不错(这里)。于是就先把网易云音乐最基本的功能实现,歌单部分(这也是我喜欢网易云音乐的原因这一),然后实现音乐的上一曲、下一曲,播放、暂停。列表功能。 后台后台采用.net做为后台提供系统请求所用的API(源码),原理很简单就是用.net伪装成一个客户端去访问网易云音乐的API然后,把返回的json数据转发出来。同时服务端做下跨域处理。 核心代码: /// vuejs部分项目结构 ├── index.html├── main.js├── api│ └── ... # 抽取出API请求├── components│ ├── playBar.vue│ └── ...└── store│ └── index.js # 整个项目的vuex部分└── router│ └── router.js # 整个项目的路由└── utils # 一些工具类模块│└── views # 项目中的一些route-view
对于整个项目来说:视图区别在于顶部导航,下面的bar的是否出来取决于,当前系统列表中是否有歌曲,如果有就会出现。 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中做统一的数据处理! 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) } }) } }})' title='' data-original-title='复制'> 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) } }) } }})
github项目地址:https://github.com/javaSwing/NeteaseCloudWebApp 目前只完成app歌单部分,也是最核心的部分。这个项目会一直更新!如果觉的不错就给个star吧 |
|