vue + typescript音乐播放器
掘金上面已经有很多播放器的实现了。这次造轮子主要是刻意练习吧,主要根据ustbhuangyi.com/music/的UI和流程实现。稍微查了下这个对应网课价格是399。。。目前只是粗略实现了主要的UI部分,数据部分都是本地的Mock数据。具体源码请戳github。
技术栈
使用了vue2.x, typescript, vue-router, swiper,better-scroll。
- vue2.x: MVVM框架
- typescript: 现在都普遍使用,主要还是为了语法检查和写代码的便利。按照现在的写法最后打包的代码会比Javascript更大。
- vue-router: 局部视图的更新和页面导航。
- swiper: 轮播幻灯片。
- better-scroll: 列表顺畅滚动。
主要设计
以下按照页面结构,导航和事件,音频播放和播放页面来讲述播放器的主要设计。
页面结构
所有的页面都在App.vue上显示,引入Header.vue, Tab.vue和ShortPlayer.vue用以显示header, tab导航和底部固定播放器。通过router-view来根据导航显示对应的推荐,歌手列表,排行,搜索,播放器等其他模块。虽然Header, Tab都放在App.vue,可以通过position:fixed, z-index来遮挡,主要不想代码重复。
推荐页面中的幻灯片滚动部分使用的Swiper对象来操作具体的dom节点,没有引入组件。列表滚动方面使用了better-scroll。使用这个部分会遇到滚动不生效的情况。一个重要的点是需要保证子节点超出了父节点的范围。同时需要传入{click:true}来保证组件内部的点击事件能够得到响应。滚动中是使用tanslateX来实现视图位移,而且需要考虑到生成BetterScroll对象的时候实际节点已经存在,节点内部结构变化的时候需要refresh。Vue使用的是虚拟节点,要Vue.nexttick的时候refresh。
导航和事件
对于简单的组件内的事件处理相对简单。如果说事件需要通知到其他的组件,那么就要设计。使用订阅和发布模式来传递数据。提供Register, Unregister, Fire接口。用一个map和数组实现即可。
export class EventHub{
private static id: number = 0
private static eventData: Map<string, Array<(data: EventData) => void>> = new Map<string, Array<(data: EventData) => void>>();
public static RegisterEvent(name: string, callback: (data: EventData) => void) {
if (!this.eventData.has(name)){
this.eventData.set(name, [])
}
this.eventData.get(name).push(callback)
}
public static UnregisterEvent(name: string, callback: (data: EventData) => void): boolean {
if (this.eventData.has(name)){
let arr = this.eventData.get(name)
for (let inx = 0; inx < arr.length; ++inx) {
if (arr[inx] === callback) {
arr.splice(inx, 1)
if (arr.length == 0) {
this.eventData.delete(name)
}
return true
}
}
}
return false
}
public static FireEvent(name: string, data: any) {
if (this.eventData.has(name)) {
let arr = this.eventData.get(name)
let event: EventData = {id: ++this.id, data: data}
for (let callback of arr) {
callback(event)
}
}
}
}
在页面导航方面,使用的hash模式,为的是简化,如果是history模式,还需要server端进行处理。
export var router = new VueRouter({
routes: [
{
path: '/', component: RecommendationComponent, meta: 0
},
{
path: '/singer', component: SingerListComponent, meta: 1
},
{
path: '/top', component: TopListComponent, meta: 2
},
{
path: '/search', component: SearchComponent, meta: 3
},
{
path: '/my', component: MySonogListComponent, meta: 0, name: "my"
},
{
path: '/full', component: FullPlayerComponent, meta: 0, name: "player"
},
{
path: '/list', component: PlayListComponent, meta: 0, name: "list"
}
],
mode: "hash"
})
在tab点击的时候,事件处理是在Tab.vue实现的,这个时候需要发出事件。
EventHub.FireEvent(EventType.HomePageTab, id)
在App.vue中,注册Tab的事件回调并更新router
switchTab(tab: EventData) {
switch(tab.data) {
case 0:
router.replace("/")
break;
case 1:
router.replace("/singer")
break;
case 2:
router.replace("/top")
break;
case 3:
router.replace("/search")
break;
}
}
音频播放
主要实现在Player.ts中实现,使用Audio对象注册对应的事件回调,并发出更新事件。FullPlayer.vue和ShortPlayer.vue来响应数据更新。
let playData: PlayerStateData = {
state: PlayerState.play,
progress: this.player.currentTime,
duration: this.player.duration,
data: this.playData
}
EventHub.FireEvent(EventType.PlayEvent, playData)
PlayControl.ts可以控制播放上下一首,达到播放模式的控制。
播放页面
主要是全屏播放页面,底部播放页面还是比较简单。第一部分是播放进度条,进度条的时候需要考虑播放的圆点本身需要占用空间,实际的进度条需要排除这个原点的宽度。
点击和拖动进度调的圆点的时候需要事件响应的节点(要使用父节点),关注touchstart, toucmove, touchend, touchcancel事件。播放进度条的宽度使用width,圆点使用abosolute方式设置left即可。
<div class="flllplayerprogresswrap" ref="progressBarRef" @touchstart="touchStart($event)" @touchcancel="touchEnd()" @touchend="touchEnd()" @touchmove="dragParnet($event)">
<div class="flllplayerprogress">
<div class="flllplayerprogresscut">
<div class="fullplayerprogresscur" :style="{width: prog + '%'}"></div>
<div class="fullplayercurdot" ref="progressDotRef" :style="{left: prog + '%'}"/>
</div>
</div>
</div>
另一个比较困难的部分就是歌词滚动。首先是歌词解析,本来想使用lyric-parser,但是发现不好用。歌词的滚动部分应该要播放进度驱动。当当前音频的currentTime更新的时候再更新。因此写一个一个简单的LyricParser能够根据传入的时间来返回应该高亮的行数。这样就不用考虑lyric-parser里面play, seek的问题。
总结
这个播放器有很多的bug,主要是为了练习设计能力,快速学习应用的能力。比如如何设计页面结构,事件处理。如果学习swiper,better-scroll并应用到实际中。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!