您好,登錄后才能下訂單哦!
這篇文章給大家分享的是有關Angular2 Service如何實現簡單音樂播放器服務的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。
引言
如果說組件系統(Component)是ng2應用的軀體,那把服務(Service)認為是流通于組件之間并為其帶來生機的血液再合適不過了。組件間通信的其中一種優等選擇就是使用服務,在ng1里就有了廣泛使用,而ng2保持了服務的全部特性,包括其全局單例與依賴注入。今天就來實踐一下ng2的服務(Service)這一利器,來實現一個簡單的音樂播放器,重點在于使用服務來進行音頻的播放控制與全局范圍的調用。
一、基本項目準備:
考慮到音頻播放是個比較通用的服務,決定將其創建為一個單獨的模塊AudioModule,并且在里面新增音頻服務主文件audio.service.ts,通用的音頻控制中心組件audio-studio.component.ts,作為輔助的TS接口文件play-data.model.ts與audio.model.ts。
最終項目音頻部分的目錄結構如圖所示:
二、創建服務:
ng2的服務,照官網的說法來解釋,其實只是個帶有Injectable裝飾器的類而已,沒有其他任何特殊的定義,所以非常簡單,不過定義如此簡單的服務卻可以完成非常多酷炫的功能。
在TypeScript下定義變量有了public與private的訪問級區分,所以定義服務通常套路就是,定義服務內使用的私有變量,在constructor構造函數中進行初始化操作,定義共有方法給服務的消費者使用。
專注于音頻播放服務的場景,我們需要的私有變量有:
1.音頻對象
①用于通過JS進行H5音頻的播放控制
2.播放列表數據
①服務內部使用的播放列表概念,實際播放音頻時都是從此列表中播放音頻,服務的消費者可以調用接口來操作此列表
3.正在播放音頻的參數
①音頻時長,當前進度以及播放模式(隨機播放之類)等
4.播放時的輪詢監聽變量
①用于音頻播放過程中自動啟動輪詢,定時(每秒)更新播放參數,當音頻暫停或停止時取消此監聽
服務初始化時需要做的事情有:
1.創建音頻對象
①可直接使用document.createElement('audio'),但不需要將其添加到DOM中。
②后續的播放控制均使用此對象來操作。
2.初始化私有變量
①私有變量中播放列表是一個數組,成員的參數使用audio.model.ts來規范化,
②必須包含一個Url參數存放播放源,以及其他可選參數
③相同的播放參數也用一個play-data.model.ts來規范化
3.給音頻添加onplay、onpause、onend等播放事件的監聽
此服務提供的公有接口包括:
1. Toggle(audio)
①判斷傳入的音頻是否已在列表中,已存在則播放或暫停,若不存在則添加進來并播放
2. Add()
①僅添加音頻到列表中
3. Remove()
①移除音頻出播放列表,需要考慮好移除后對播放隊列的影響,比如是否是正在播放的音頻被移除等等
4. Next()
5. Prev()
上一曲與下一曲操作,需要考慮到播放模式
6. Skip()
進行播放進度的跳轉
7. PlayList()
8. PlayData()
①用于暴露服務所維護的兩個數據(播放列表與播放參數),在指令中都是通過這兩個接口來呈現數據的
服務的完整代碼如下:
import { Injectable } from '@angular/core'; import { Audio } from './audio.model'; import { PlayData } from './play-data.model'; /** * 音頻服務,只關心播放列表控制與進度控制 * 不提供組件支持,只提供列表控制方法接口及進度控制接口 */ @Injectable() export class AudioService { // 主音頻標簽 private _audio: HTMLAudioElement; // 當前列表中的音頻 private playList: Audio[]; // 當前播放的數據 private playData: PlayData; private listenInterval; /** * 創建新的音頻標簽 */ constructor() { this._audio = document.createElement('audio'); this._audio.autoplay = false; this._audio.onplay = () => { let that = this; this.listenInterval = window.setInterval(() => { that.playData.Current = that._audio.currentTime; that.playData.Url = that._audio.src; that.playData.During = that._audio.duration; that.playData.Data = that._audio.buffered && that._audio.buffered.length ? (that._audio.buffered.end(0) || 0) : 0; }, 1000); this.playData.IsPlaying = true; }; this._audio.onended = () => { window.clearInterval(this.listenInterval); this.FillPlayData(); this.playData.IsPlaying = false; }; this._audio.onabort = () => { window.clearInterval(this.listenInterval); this.playData.Current = this._audio.currentTime; this.playData.Url = this._audio.src; this.playData.During = this._audio.duration; this.playData.Data = this._audio.buffered && this._audio.buffered.length ? (this._audio.buffered.end(0) || 0) : 0; this.playData.IsPlaying = false; }; this._audio.onpause = () => { window.clearInterval(this.listenInterval); this.playData.Current = this._audio.currentTime; this.playData.Url = this._audio.src; this.playData.During = this._audio.duration; this.playData.Data = this._audio.buffered && this._audio.buffered.length ? (this._audio.buffered.end(0) || 0) : 0; this.playData.IsPlaying = false; }; this.playData = { Style: 0, Index: 0 }; this.playList = []; } /** * 1.列表中無此音頻則添加并播放 * 2.列表中存在此音頻但未播放則播放 * 3.列表中存在此音頻且在播放則暫停 * @param audio */ public Toggle(audio?: Audio): void { let tryGet = audio ? this.playList.findIndex((p) => p.Url === audio.Url) : this.playData.Index; if (tryGet < 0) { this.playList.push(audio); this.PlayIndex(this.playList.length); } else { if (tryGet === this.playData.Index) { if (this._audio.paused) { this._audio.play(); this.playData.IsPlaying = true; } else { this._audio.pause(); this.playData.IsPlaying = false; } } else { this.PlayIndex(tryGet); } } } /** * 若列表中無此音頻則添加到列表的最后 * 若列表中無音頻則添加后并播放 * @param audio */ public Add(audio: Audio): void { this.playList.push(audio); if (this.playList.length === 1) { this.PlayIndex(0); } } /** * 移除列表中指定索引的音頻 * 若移除的就是正在播放的音頻則自動播放新的同索引音頻,不存在此索引則遞減 * 若只剩這一條音頻了則停止播放并移除 * @param index */ public Remove(index: number): void { this.playList.splice(index, 1); if (!this.playList.length) { this._audio.src = ''; } else { this.PlayIndex(index); } } /** * 下一曲 */ public Next(): void { switch (this.playData.Style) { case 0: if (this.playData.Index < this.playList.length) { this.playData.Index++; this.PlayIndex(this.playData.Index); } break; case 1: this.playData.Index = (this.playData.Index + 1) % this.playList.length; this.PlayIndex(this.playData.Index); break; case 2: this.playData.Index = (this.playData.Index + 1) % this.playList.length; this.PlayIndex(this.playData.Index); console.log('暫不考慮隨機播放將視為列表循環播放'); break; case 3: this._audio.currentTime = 0; break; default: if (this.playData.Index < this.playList.length) { this.playData.Index++; this.PlayIndex(this.playData.Index); } break; } } /** * 上一曲 */ public Prev(): void { switch (this.playData.Style) { case 0: if (this.playData.Index > 0) { this.playData.Index--; this.PlayIndex(this.playData.Index); } break; case 1: this.playData.Index = (this.playData.Index - 1) < 0 ? (this.playList.length - 1) : (this.playData.Index - 1); this.PlayIndex(this.playData.Index); break; case 2: this.playData.Index = (this.playData.Index - 1) < 0 ? (this.playList.length - 1) : (this.playData.Index - 1); this.PlayIndex(this.playData.Index); console.log('暫不考慮隨機播放將視為列表循環播放'); break; case 3: this._audio.currentTime = 0; break; default: if (this.playData.Index > 0) { this.playData.Index--; this.PlayIndex(this.playData.Index); } break; } } /** * 將當前音頻跳轉到指定百分比進度處 * @param percent */ public Skip(percent: number): void { this._audio.currentTime = this._audio.duration * percent; this.playData.Current = this._audio.currentTime; } public PlayList(): Audio[] { return this.playList; } public PlayData(): PlayData { return this.playData; } /** * 用于播放最后強行填滿進度條 * 防止播放進度偏差導致的用戶體驗 */ private FillPlayData(): void { this.playData.Current = this._audio.duration; this.playData.Data = this._audio.duration; } /** * 嘗試播放指定索引的音頻 * 索引不存在則嘗試遞增播放,又失敗則遞減播放,又失敗則失敗 * @param index */ private PlayIndex(index: number): void { index = this.playList[index] ? index : this.playList[index + 1] ? (index + 1) : this.playList[index - 1] ? (index - 1) : -1; if (index !== -1) { this._audio.src = this.playList[index].Url; if (this._audio.paused) { this._audio.play(); this.playData.IsPlaying = true; } this.playData.Index = index; } else { console.log('nothing to be play'); } } }
三、使用服務:
接下來要使用服務了,再ng2中服務也要依賴具體的模塊,我們得音頻服務依賴的就是自己的音頻模塊,在模塊的provider列表中配置它:
@NgModule({ imports: [ CommonModule, SharedModule ], declarations: [ AudioStudioComponent ], exports: [ AudioStudioComponent ], providers: [ AudioService ] })
接下來要實現服務的消費者——AudioStudioComponent 了,步驟如下:
1.在構造函數中注入服務:
constructor(public audio: AudioService) { }
2.使用Add()方法添加音頻:
audio.Add({Url: '/assets/audio/唐人街.mp3', Title: '唐人街-林宥嘉', Cover: '/assets/img/2219A91D.jpg'}); audio.Add({Url: '/assets/audio/自然醒.mp3', Title: '自然醒-林宥嘉', Cover: '/assets/img/336076CD.jpg'});
Add方法添加的音頻如果是列表中僅有的一條音頻則會直接播放,所以如此添加兩條音頻會直接播放第一條音頻。
再在組件內實現一個Skip方法用于進度控制:
public Skip(e) { this.audio.Skip(e.layerX / document.getElementById('audio-total').getBoundingClientRect().width); }
現在運行項目:
音頻播放器的樣式是崩塌的...因為這個組件是筆者另一個項目中直接copy過來了,在此demo項目中還沒加上移動端rem適配,尷尬,不過大概的效果是展現出來了。
感謝各位的閱讀!關于“Angular2 Service如何實現簡單音樂播放器服務”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。