导航
导航
文章目录
  1. 预览地址: http://hzzly.net/magic-music
  2. Github地址: https://github.com/hzzly/MagicMusic
  3. 实现的功能
    1. 1、首页
    2. 2、底部播放控件
    3. 3、播放页面
    4. 4、播放列表
    5. 5、排行榜
    6. 6、音乐搜索
    7. 7、侧边栏
  4. API
  5. 目录结构
  6. 开发心得与总结
    1. 1、轮播图
    2. 2、歌曲操作(喜欢,分享,加入播放列表)动画、播放列表展开与删除歌曲动画
    3. 3、直线进度条、弧形进度条
    4. 4、本地存储
    5. 5、图片懒加载
    6. 6、歌词滚动与高亮
    7. 7、vuex状态管理

DIY一个自己的音乐播放器

前言:在最近的一个外包项目中包联盟(PC端)中使用到了video,遇到了好多坑。突发奇想来踩一踩audio的坑😀,果然一入深似海,👇下面将分享我的DIY之路-Vue音乐播放器。
注:本项目为开源项目,不能用于商业应用,仅供学习。有问题或建议发我邮箱:hjingren@aliyun.com

[温馨提示:pc浏览f12手机模式最佳,手机建议wifi下访问]

预览地址: http://hzzly.net/magic-music

Github地址: https://github.com/hzzly/MagicMusic

欢迎大家的star啦😄~

先来个预览:

magic-music1

更多预览:更多

👉老铁们,准备发车(技能点):

👉坐好,出发

实现的功能

1、首页

  • [x] 轮播
  • [x] 个性推荐[流行、古典、轻音乐、流行]
  • [x] 歌曲操作
    • [x] 加入播放列表
    • [ ] 喜欢
    • [ ] 分享

2、底部播放控件

  • [x] 播放
  • [x] 暂停
  • [x] 下一曲
  • [x] 播放进度条

3、播放页面

  • [x] 上一曲
  • [x] 播放
  • [x] 暂停
  • [x] 下一曲
  • [x] 播放进度条[弧形进度条]
  • [x] 歌词滚动
  • [x] 播放的歌词高亮
  • [ ] 播放模式[单曲循环、列表循环、随机播放]

4、播放列表

  • [x] 播放歌曲高亮
  • [x] 切歌(单击切歌)
  • [x] 删歌(点击右侧小X)
  • [ ] 清空播放列表
  • [ ] 本地缓存播放列表

5、排行榜

  • [x] 热门排行榜
  • [x] 排行榜里的歌曲(单击播放)

6、音乐搜索

输入搜索关键词,点击放大镜图标

  • [x] 单曲(单击或点击歌曲操作(…)添加至音乐播放列表,部分音乐会存在版权问题无法播放)
  • [x] 歌手
  • [x] 专辑
  • [x] 歌单
  • [x] 用户
  • [x] 本地缓存搜索列表

7、侧边栏

  • [x] 头像
  • [x] 菜单
    • [x] 个人中心

API

感谢作者把api整理的这么好(点个赞👍)

网易云音乐 NodeJS 版 API

目录结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|——MagicMusic/
| |——build/
| |——confg/
| |——node_modules/
| |——src/
| | |——assets/ //静态文件
| | |——components/ //公共组件
| | |——api/
| | | |——index.js //axios封装与api
| | |——pages/ //存放项目页面
| | | |——classical.vue //古典歌曲页面
| | | |——collection.vue //排行榜
| | | |——home.vue //首页
| | | |——light.vue //轻音乐歌曲页面
| | | |——login.vue //登录页面
| | | |——popular.vue //流行歌曲页面
| | | |——radio.vue //电台歌曲页面
| | | |——rank.vue //排行榜列表
| | | |——search.vue //搜索页
| | | |——user.vue //用户
| | |——router/
| | | |——index.js //页面路由
| | |——util //公用方法
| | |——vuex / //存放vuex代码
| | | |——modules / //数据模块
| | | |——store.js //vuex主入口
| | | |——types.js //vuex的types文件
| | |——App.vue //父组件
| | |——main.js //入口文件
| |——static/
| |——.babelrc
| |——.editorconfig
| |——.gitgnore
| |——index.html
| |——package.json
| |——README.md

开发心得与总结

1、轮播图

首先感谢作者ShanaMaid/vue-image-scroll开源的代码,我把代码copy下来自己进行了一点修改(没有手指滑动效果),因为这是移动端,少不了的手指滑动切换,所以添加了vue-touch(偷偷告诉你,vue-touch的next分支还是支持vue2.0的😜)。代码传送门

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<li v-for="(item,index) in image" :class="[move[index]]">
<v-touch class="vuetouch"
v-on:swipeleft="nextPic"
v-on:swiperight="prePic">
...
</v-touch>
</li>
methods: {
nextPic(event) {
let temp = this.move.pop()
this.move.unshift(temp)
},
prePic(event) {
let temp = this.move.shift()
this.move.push(temp)
},
}

2、歌曲操作(喜欢,分享,加入播放列表)动画、播放列表展开与删除歌曲动画

Vue提供了transition的封装组件,在下列情形中,可以给任何元素和组件添加 entering/leaving 过渡

  • 条件渲染 (使用 v-if)
  • 条件展示 (使用 v-show)
  • 动态组件
  • 组件根节点
1
2
3
4
5
6
7
8
9
10
<transition name="move">
<div class="menu" v-show="item.menuShow">
...
</div>
</transition>
<transition-group name="slide" tag="div" class="list-wrapper">
<div class="item" v-for="(item, index) in listenLists" :key="item">
...
</div>
</transition-group>

transition-group一组过度动画,这里有个小坑的,之前看官网列表过渡的栗子,给每一项设置唯一的key值,一般都会用index。所以在做的时候就把index传给key,结果过渡老是不对,后来换成对应的item就正常了(生无可恋脸)。

3、直线进度条、弧形进度条

西班牙建筑大师曾说过:“直线属于人类,曲线则归于上帝”。在这里我大胆的使用了弧形来作为进度条,(几大热门音乐APP貌似还没有弧形进度条😄)。

这里我用到了Vue的绑定内联样式

1
2
3
4
5
6
7
8
9
10
11
12
//直线进度条
<div class="progress-bar">
<div class="play"
:style="{width: (now / duration).toFixed(3)*100 + '%'}"></div>
</div>
//弧形进度条
//因为用到了弧形,所以我这里用到了`border-radius`来使它变成一个大圆,然后平移`translateX`居中,其它不要的部分`overflow: hidden`。
//这里用两个div来表示进度条,一条固定的进度条,一条慢慢增加。
<div class="process" @click="showToast">
<div class="line"></div>
<div class="pro" :style="{transform: `translateX(${translateX}) rotate(${deg*1 + 56.5*((now / size).toFixed(3))}deg)`}"></div>
</div>

4、本地存储

将一些数据缓存到localStorage,可以减少Http请求,从而优化页面加载时间。

在这个项目中首页歌曲列表以及搜索历史用到了本地缓存,拿搜索历史来举栗:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
created() {
if (!localStorage.searchHistory) {
let searchHistory = ['前端', '童话镇', '刚好遇见你']
localStorage.searchHistory = JSON.stringify(searchHistory)
}
},
methods: {
_search(keywords) {
//判断搜索列表中是否已存在
let searchHistory = JSON.parse(localStorage.searchHistory)
let find = searchHistory.findIndex((val) => {
return val === keywords
})
find === -1 ? localStorage.searchHistory = JSON.stringify([keywords, ...searchHistory]) : ''
}
}

5、图片懒加载

使用了vue-lazyload插件
用法👉:

1
$ npm install vue-lazyload

1
2
3
4
5
6
7
8
9
//main.js
import VueLazyLoad from 'vue-lazyload'
import def_lazy_img from '../static/img/loading.gif' //懒加载的默认图片
Vue.use(VueLazyLoad,{
loading: def_lazy_img
}) //使用懒加载组件
//在使用img标签的地方使用
<img v-lazy="item.al.picUrl" alt="">

6、歌词滚动与高亮

因为api提供的歌词包括时间,如:[03:57.280]原谅我这一生不羁放纵爱自由
所以首先要进行字符串切割:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<div class="lyric">
<div class="roll-lyric" v-html="lyrics" ref="lyric"></div>
</div>
computed: {
lyrics() {
let lyrics = ''
this.lyricArr = []
if (this.lyric) {
let arr = this.lyric.split('\n')
for (let item of arr) {
if (item) {
let arr2 = item.split(']')
this.lyricArr.push(arr2[0].substring(1,3)*60+arr2[0].substring(4)*1)
if (arr2) {
lyrics += `<p class='lyrichook' style='margin: 10px 0'>${arr2[1]}</p>`
}
}
}
} else {
lyrics = '暂无歌词~'
}
return lyrics
}
}

然后在播放的监听事件中与播放的当前做对比:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
this.$refs.myAudio.addEventListener('play', () => {
this.pDOM = [...document.querySelectorAll('.lyrichook')]
timer = setInterval(() => {
this.now = audioDOM.currentTime
this.lyricArr.forEach((item, index) => {
if (parseInt(item) == parseInt(this.now)) {
this.pDOM.forEach((p) => {
p.style.color = 'rgba(255,255,255,.8)' //其它歌词清除高亮
});
this.pDOM[index].style.color = '#f12c61' //歌词高亮
this.$refs.lyric.style.transform = `translateY(-${(index-2)*25}px)` //歌词滚动
}
});
}, 1000)
})

到这就ok了😜

7、vuex状态管理

推荐官方调试工具 devtools extension

想进一步理解vuex,可以看这篇博客vuex学习实践笔记

之前看到好多人写的vuex,把整个项目的数据放到了一个state里,导致应用的所有状态集中到一个很大的对象。但是,当应用变得很大时,store 对象会变得臃肿不堪。

所以我建议(个人见解,轻喷):将 store 分割到模块(module)。每个模块拥有自己的 state、mutation、action、getters。这样方便管理与后期的维护。

车已到站✌️。

不知不觉写了这么多,老铁们凑合这看吧😁,觉得还行的可以点个star,你的star是我继续开源创作的动力,谢谢!!!

项目地址: https://github.com/hzzly/MagicMusic
欢迎大家的star啦~

支持一下
谢谢你请我吃糖果