前言:在最近的一个外包项目中包联盟(PC端)中使用到了video,遇到了好多坑。突发奇想来踩一踩audio的坑?,果真一入深似海,?下面将分享个人DIY之路-Vue音乐播放器。
注:本项目为开源项目,不能用于商业应用,仅供学习。有问题或建议发我邮箱:hjingren@aliyun.comjavascript
[舒适提示:pc浏览f12手机模式最佳,手机建议wifi下访问]
demo地址: http://hzzly.net/magic-music(因api不稳定,预览效果不佳,能够clone项目和api在本地运行)
项目地址: https://github.com/hzzly/MagicMusic
欢迎你们的star啦?~html
先来个预览:前端
更多预览:更多vue
?老铁们,准备发车(技能点):java
vue文档node
vue-router文档webpack
vuex文档 不想看文档的能够看看我这篇博客vuex学习实践笔记ios
axios文档 或者这篇博客 Vuex2 与 Axios 开发(我也是参考这篇,感谢做者?)git
es6(阮一峰的es6入门) 能够参考个人es6之路(还在继续,轻喷)es6
?坐好,出发
[x] 轮播
[x] 个性推荐[流行、古典、轻音乐、流行]
[x] 歌曲操做
[x] 加入播放列表
[ ] 喜欢
[ ] 分享
[x] 播放
[x] 暂停
[x] 下一曲
[x] 播放进度条
[x] 上一曲
[x] 播放
[x] 暂停
[x] 下一曲
[x] 播放进度条[弧形进度条]
[x] 歌词滚动
[x] 播放的歌词高亮
[ ] 播放模式[单曲循环、列表循环、随机播放]
[x] 播放歌曲高亮
[x] 切歌(单击切歌)
[x] 删歌(点击右侧小X)
[ ] 清空播放列表
[ ] 本地缓存播放列表
[x] 热门排行榜
[x] 排行榜里的歌曲(单击播放)
输入搜索关键词,点击放大镜
图标
[x] 单曲(单击或点击歌曲操做(...)添加至音乐播放列表,部分音乐会存在版权问题没法播放)
[x] 歌手
[x] 专辑
[x] 歌单
[x] 用户
[x] 本地缓存搜索列表
[x] 头像
[x] 菜单
[x] 我的中心
感谢做者把api整理的这么好(点个赞?)
|——MagicMusic/ | |——build/more--> | |——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
首先感谢做者ShanaMaid/vue-image-scroll开源的代码,我把代码copy下来本身进行了一点修改(没有手指滑动效果),由于这是移动端,少不了的手指滑动切换,因此添加了vue-touch(偷偷告诉你,vue-touch的next分支仍是支持vue2.0的?)。代码传送门
<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) }, }
Vue
提供了transition
的封装组件,在下列情形中,能够给任何元素和组件添加 entering/leaving 过渡
条件渲染 (使用 v-if)
条件展现 (使用 v-show)
动态组件
组件根节点
<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
就正常了(生无可恋脸)。
西班牙建筑大师曾说过:“直线属于人类,曲线则归于上帝”。在这里我大胆的使用了弧形来做为进度条,(几大热门音乐APP貌似尚未弧形进度条?)。
这里我用到了Vue的绑定内联样式
//直线进度条 <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>
将一些数据缓存到localStorage,能够减小Http请求,从而优化页面加载时间。
在这个项目中首页歌曲列表以及搜索历史用到了本地缓存,拿搜索历史来举栗:
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]) : '' } }
使用了vue-lazyload插件
用法?:
$ npm install vue-lazyload
//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="">
由于api提供的歌词包括时间,如:[03:57.280]原谅我这一辈子不羁放纵爱自由
因此首先要进行字符串切割:
<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 } }
而后在播放的监听事件中与播放的当前作对比:
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了?
推荐官方调试工具 devtools extension
想进一步理解vuex,能够看这篇博客vuex学习实践笔记
以前看到好多人写的vuex,把整个项目的数据放到了一个state里,致使应用的全部状态集中到一个很大的对象。可是,当应用变得很大时,store 对象会变得臃肿不堪。
因此我建议(我的看法,轻喷):将 store 分割到模块(module)。每一个模块拥有本身的 state、mutation、action、getters。这样方便管理与后期的维护。
车已到站✌️。
不知不觉写了这么多,老铁们凑合这看吧?,以为还行的能够点个star,你的star是我继续开源创做的动力,谢谢!!!
项目地址: https://github.com/hzzly/MagicMusic
欢迎你们的star啦~
文章来源:hzzly技术分享