前言

基于 Vue + vuex + vue-router + vue-axios +better-scroll + Stylus + px2rem
等开发的移动端音乐App,UI 界面是看着自己手机的网易云音乐写的、flex 布局适配常见移动端。

也许是服务器原因有时进入页面首页,左右滑动切换页面效果没有用。这时请重新刷
新页面,有时页面加载的有点慢,请耐心等待。

写这个呢是因为最近学了Vue,想巩固下自己所学的知识。个人认为写项目可以更好的发现自己的不足。写音乐呢是因为网易有开源的接口,还有自己喜欢听歌!

炎炎夏日,你在家里吹着空调吃着冰镇西瓜没准还躺在沙发上看着自己喜欢的电影。而我却在学校看着电脑敲着代码没准还正抓着头皮改着不知道哪里出错了的bug。来自大三在校生的感慨,所以大佬请轻喷!!但我的问题请大佬务必告知,或者有更好的解决方案也一样,毕竟谁不想学到更多的知识呢?

页面预览

没有切图就是看着手机自己写的,所以样式有点难看。

我的 发现 朋友(还没写) 视频


歌单 排行榜

歌单详情 个人中心

全屏播放 搜索页面

开发目的

记录自己的学习,因为有些东西你不用它遗忘的是很快的。希望以后想捡起来的时候看看自己的笔记能有所帮助。就算没啥帮助,等多年以后回头看看自己曾经写的代码,也挺有意思的!

技术栈

Vue: 用于构建用户界面的 MVVM 框架

Vue-router: 单页面应用提供的路由管理

vuex:Vue集中状态管理,大型项目所必需的数据存储,让多个组件相互交互、共享状态时非常便捷

better-scroll:解决移动端各种滚动场景需求的插件,使移动端滑动体验更加流畅

stylus: 一种Css预编译处理器

px2rem: 移动端自适应的一种方法

Vue-axios: 用于请求API接口

NeteaseCloudMusicApi:网易云音乐 NodeJS 版 API,提供音乐数据

iconfont :阿里巴巴图标库,十分强大的一个图标库

页面架构

api

axios方法封装

axios.defaults.timeout = 10000
axios.defaults.baseURL = 'http://localhost:3000'// 返回状态判断
axios.interceptors.response.use((res) => {if (res.data.code !== 200) {console.log('网络异常')vue.$toast('网络异常')vue.$hideLoading()return Promise.reject(res)}return res
}, (error) => {console.log('网络异常')vue.$toast('网络异常')vue.$hideLoading()return Promise.reject(error)
})export function fetchGet(url, param) {return new Promise((resolve, reject) => {axios.get(url, {params: param}).then(response => {resolve(response.data)}, err => {reject(err)}).catch((error) => {reject(error)})})
}

axios接口请求(只展示几条避免太冗长)

export default {//歌单DiscLists(params) {return fetchGet('/top/playlist', params)},// 歌单详情SongList(params) {return fetchGet('/playlist/detail', params)},//歌曲搜索MusicSearch(params){return fetchGet('/search',params)},//获取歌曲的urlMusicUrl (id){return fetchGet('/top/playlist',{id})},//根据id获取mv数据getMVDetail(params){return fetchGet('/mv/detail', params)},//手机号登录phoneLogin(params){return fetchGet('/login/cellphone', params)},//登录后根据用户id获取用户歌单getUserSonglist(params){return fetchGet('/user/playlist', params)},
}

router(只展示部分)

 routes: [主页面{path: '/', component: Main},{//歌单详情页path: '/songdetail',name:songdetail,component: songdetail},//歌单广场{path: '/songSquare/songSquare',name:songSquare,component: songSquare},//搜索页{path: '/search',name:search,component: search},//搜索详情页{path: '/searchDetail',name:searchDetail,component: searchDetail},]

Vuex

modules(只展示music)

import * as types from '../types'const state = {songlist : [],songs : '可乐',searchHistory : ['薛之谦']
}const mutations = {// 上拉刷新歌单[types.RESH_SONG_LIST](state, songlist) {state.songlist = songlist;// console.log(state.songlist)},//保存搜索历史[types.SAVE_SEARCH_HISTORY](state, searchHistory) {//数组去重,避免用户搜索相同关键字多次而加入相同的关键字if(!state.searchHistory.includes(searchHistory)){state.searchHistory.unshift(searchHistory)}// console.log(state.searchHistory)},//删除搜索历史 DELETE_SEARCH_HISTORY[types.DELETE_SEARCH_HISTORY](state) {state.searchHistory = []},
}const actions = {// 上拉刷新歌单reshSongList ({commit, state}, songlist) {console.log(songlist);// let playHistory = state.playHistory.slice()// playHistory = [...playHistory, song]commit(types.RESH_SONG_LIST, songlist)},//保存搜索历史saveSearchHistory({commit, state}, searchHistory) {console.log(searchHistory);commit(types.SAVE_SEARCH_HISTORY, searchHistory)},//删除搜索历史 DELETE_SEARCH_HISTORYdeleteSearchHistory({commit, state}) {commit(types.DELETE_SEARCH_HISTORY)},
}const getters = {songlist: state => state.songlist,songs : state => state.songs,searchHistory : state => state.searchHistory,
}export default {state,mutations,actions,getters
}

types(刚开始还记得常量应该大写,写着写着就忘了!尴尬)

export const RESH_SONG_LIST = 'RESH_SONG_LIST' // 刷新歌单
export const SAVE_SEARCH_HISTORY = 'SAVE_SEARCH_HISTORY'//保存搜索历史
export const DELETE_SEARCH_HISTORY = 'DELETE_SEARCH_HISTORY'//删除搜索历史
export const yuncun_video = 'yuncun_video'//获取云村精选视频
export const inland_video = 'inland_video'//获取内地视频
export const hongkong_video = 'hongkong_video'//获取港台视频
export const occident_video = 'occident_video'//获取欧美视频
export const japan_video = 'japan_video'//获取日本视频
export const update_login = 'update_login'//修改登录状态
export const save_userId = 'save_userId'//保存用户id
export const save_profile = 'save_profile'//保存用户信息
export const save_songlist = 'save_songlist'//保存用户歌单
export const save_userDetail = 'save_userDetail'//保存用户详情

store.js(将模块导出)

import Vue from 'vue'
import Vuex from 'vuex'// import com from './modules/com'
import music from './modules/music'
import video from './modules/video'
import myLogin from './modules/myLogin'Vue.use(Vuex)export default new Vuex.Store({modules : {music,video,myLogin,}
})

主要功能

推荐页面、歌单详情、歌单广场页面、排行榜详情、搜索页面、歌手列表、播放列表、个人中心等功能。

发现页面

页面切换

左右滑动实现页面切换,随着页面的切换顶部的tab也随之切换高亮。想了解请看这篇文章

上拉刷新

上拉刷新,推荐歌单会更新,数据是由Vuex管理的。还用了随机获取6条数据并做了数组去重,以免获取到两条相同的歌单数据。最大的败笔就是这个下拉刷新的位置其实是写错了位置的,导致不管在哪个tab页下拉刷新,发现页面的歌单都会更新,导致我好多页面不好写下拉刷新功能。我TM后面才发现的,很难受!上拉加载方法本来定义好了搞得也不能用了,当时脑袋发热觉得放在这其他页面就不用再重复写了。

      api.Recommend(params).then(res =>{if(res.code === 200){this.songlist = [];let length = res.playlists.lengthwhile(this.songlist.length<6){var random = Math.floor(Math.random()*(length-6+1)+1);//数组去重if (!this.songlist.includes(res.playlists[random])) {this.songlist.push(res.playlists[random]);}}this.$store.dispatch("reshSongList",this.songlist)}})

歌单详情页

这个页面的父子组件的传值方式用了好几种方法

  1. <i-button size=“large” @click.native=“handleClick”>提交
  2. 在子组件中加上ref即可通过this.$refs.ref.method调用

想了解更多方法请点这里

之前学习的时候以为只有一种,但当时感觉用第一种这种方法有点麻烦,就去百度了一下,发现还有好多方法。所以写项目还是可以学到更多知识的

这个页面应该最复杂的一个页面了,当时没考虑的好,知道页面要复用,但还是没有设计的很好,导致有几个页面还是复制代码改了传入的数据。如果当时数据全部是由父组件传过来的话,设计的好一点,一个详情页就可以了。

下面是这个页面的部分方法,比较多我就用图片形式展示了

歌单详情页中用了个组件,也就是底部播放

  watch:{index (val){const params = {id: this.songs[val].id};immediate: true;this.play();api.SongUrl(params).then( (res)=>{this.songdata = res.data;this.$refs.audio.src = this.songdata[0].url;this.songAvtart = this.songs[val].al.picUrl;this.songname = this.songs[val].name;this.singer = this.songs[val].ar[0].name;console.log(res.data)}).then(()=>{// this.$refs.audio.play();this.play();this.$emit('play');// this.con = false;})},},

用watch监听,父组件传过来的index值,从而点击哪首歌播放哪首歌

下面是底部播放器中的方法

 methods:{//歌曲播放完自动播放下一首ended(){//子组件调用父组件的方法console.log('father');this.$parent.next();},//播放音乐play () {console.log(this.$refs.audio)this.$refs.audio.play();this.con = false;//图片旋转this.rotate = true;//告诉父组件正在播放this.$emit('play');},//暂停音乐pause(){this.con = true;this.$refs.audio.pause();//停止旋转this.rotate = false;//告诉父组件暂停播放this.$emit('pause');},//全屏播放fullPlay(){this.$emit('fullPlay');}},

歌单广场页


这个页面基本和发现页面一样,就不赘述了.

排行榜详情


排行榜页面和歌单广场页面类似不再赘述

搜索页面

1.可以在输入框中输入你想搜索的歌曲
2.也可以点击搜索历史搜索
3.点击热搜榜也可以搜索

歌手页

只有个上拉加载功能

歌手页最开始是想写成有字母索引导航的,但当时被一个better-scroll搞崩了。
后来百度才知道,用better-scroll有四个必须条件,具体使用方法请点这里

  1. 必须包含两个大的div,外层和内层div
  2. 外层div设置可视的大小(宽或者高)-有限制宽或高
  3. 内层div,包裹整个可以滚动的部分
  4. 内层div高度一定大于外层div的宽或高,才能滚动

我的页面

第一次去到我的页面,如果没登录的话,需要先登录。登录完之后用户id会保存在
Vuex中。

视频页面

也没啥好说的,点击视频播放就完事了。每次只能播放一个视频

未来想写的

  1. 把朋友界面写一下
  2. 有些功能还是有问题的,需要完善
  3. 优化下重复的代码
  4. 再增加一些功能,因为还有好多功能没写。目前正在学react,没有太多时间
  5. github地址

致谢

十分感谢蜗牛老师教的Vue课程,蜗牛老师讲课是真的透彻!

最后

最后送自己一句话:你抓头改bug的样子虽然有些狼狈,但你努力写代码的样子真的很帅!!共勉。

[Vue仿网易云音乐实战]炎炎夏日——放首自己喜欢的歌相关推荐

  1. 毕业设计:基于Springboot + Vue仿网易云音乐网站(一)开源

    项目背景 最近自学了springboot.vue.redis等技术,为了巩固,决定自己做个小网站玩玩,把学到的东西都使用一下,因为自己比较喜欢听音乐,去年一年网易云就听了1800个小时,然后也喜欢周杰 ...

  2. 2019 Electron+Vue+Ant Design Vue仿网易云音乐windows客户端实战分享

    特点 拖拽播放 桌面歌词 mini模式 自定义托盘右键菜单 任务栏缩略图,歌曲操作 音频可视化 自动/手动检查更新 Nedb数据库持久化 自定义安装路径,安装界面美化 浏览器中启动客户端 Travis ...

  3. Vue仿网易云音乐播放器(一)

    项目简介 写了很多关于Vue的项目,都是一部分一部分的小模块,这次想把全部学过的关于Vue知识和模块写成一个完整的项目.都是组件化进行mvvm模式开发,实现了view和data的同步更新.仿网易云播放 ...

  4. SpringBoot+vue仿网易云音乐网站(二)-数据库设计

    一.需求分析 仿网易云,那么需求的话就照着网易云音乐来做了. 首先可以听歌,可以查看歌手,歌手又有对应的专辑,有用户,用户可以新建歌单,收藏歌单,歌单可以增删歌曲,用户还可以评论歌曲.专辑.歌单,还有 ...

  5. Vue仿网易云音乐播放器(二)

    项目运行 首先要安装npm或者cnpm和node.js环境 在终端建立vue-cli项目,命令行cnpm install vue-cli -g //全局安装 vue-cli 查看vue-cli是否成功 ...

  6. SpringBoot+vue仿网易云音乐网站(三)- Springboot项目以及前端vue基础搭建

    一.基础项目搭建 1. 新建springboot项目 在搭建Springboot项目之前,需要的基础环境:JDK(8).Maven,工具Idea.项目就新建一个简单的springboot项目就行了,具 ...

  7. vue 仿网易云音乐项目

    感谢 Binaryify 预览地址 desktop-nicemusic gitee 项目地址 项目截图 登录 首页 个人中心 歌单页面 其它 目前正在开发react版本,ui会更改一些然后功能会再加入 ...

  8. 一款仿网易云音乐Java开源系统(附源码)

    嗨喽!Java后端编程的各位小伙伴们,由于公众号做了乱序推送改版,为了保证公众号的推文能够第一时间及时送达到大家手上,大家记得将公众号 加星标置顶 ,公众号每天会送上Java技术干货推文 ! 上篇推文 ...

  9. 高仿网易云音乐(vue实战项目)

    高仿网易云音乐(Vue实战项目)

最新文章

  1. LinuxMint 14 更新源(能成功的!)
  2. 微软研究员:fork() 已落后,需要淘汰
  3. java 连接 postgresql_java如何连接数据库并对其操作(以PostgreSQL为例)
  4. ZOJ 1970 All in All
  5. MySQL ERROR 1045 (28000): Access denied for user 'root'@'192.168.23.224' (using password: YES)
  6. 根据MAC地址修改固定IP(附带IPMAC扫描脚本)
  7. python字典浅复制_元组,字典,浅复制,集合
  8. 5.业务架构·应用架构·数据架构实战 --- 业务驱动的数据架构设计
  9. Google全球服务器根域名的IP地址
  10. 白帽子讲web安全(一)
  11. 全国一级计算机考证软件
  12. java后端使用itextPDF生成PDF文件
  13. 排序算法--鸽巢排序(PigeonholeSort)的原理、排序思路、适用场景及代码示例
  14. [BZOJ3772]精神污染 主席树上树+欧拉序
  15. 在有n个学生的成绩表里,每条信息由姓名与分数组成,要求:1按分数高低次序,输出每个学生的名字,分数相同的为同一名次,2按名次输出每个学生的姓名与分数。
  16. 计算机锁定不能强制选项无法关机,Win10无法关机只能按电源强制关机的解决方法...
  17. 2022安全员-A证考试题模拟考试题库模拟考试平台操作
  18. 厌倦城市,我逃往中国最南小镇,成为一个渔民
  19. 教程 | Python实战 模拟登陆百度云盘
  20. python - pandas 之 dataframe - 行列筛选/遍历/新增/删除/连接/合并/修改/跨表update

热门文章

  1. Linux 块设备 EMMC 驱动介绍
  2. 信息系统分析与设计——信息系统建设
  3. 360 手机助手爬虫
  4. 无人机拍滑雪不够酷,用GoPro Omni VR如何?
  5. 没用过TheBrain,请别叫它“思维导图” | TheBrain深度解析
  6. [FAQ17853]M上默认接入点apn显示
  7. MAX30100心率血氧模块
  8. css设计软件dw,教你在Dreamweaver中使用CSS设计布局
  9. 魔百和M401A刷入Armbian系统EMMC
  10. 重回童年4399| 【黄金矿工】游戏制作+解析