欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Angular2 Service實(shí)現(xiàn)簡(jiǎn)單音樂播放器服務(wù)

 更新時(shí)間:2017年02月24日 09:00:00   作者:Yitim  
本篇文章主要介紹了Angular2 Service實(shí)現(xiàn)簡(jiǎn)單音樂播放器服務(wù) ,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧

引言

如果說組件系統(tǒng)(Component)是ng2應(yīng)用的軀體,那把服務(wù)(Service)認(rèn)為是流通于組件之間并為其帶來生機(jī)的血液再合適不過了。組件間通信的其中一種優(yōu)等選擇就是使用服務(wù),在ng1里就有了廣泛使用,而ng2保持了服務(wù)的全部特性,包括其全局單例與依賴注入。今天就來實(shí)踐一下ng2的服務(wù)(Service)這一利器,來實(shí)現(xiàn)一個(gè)簡(jiǎn)單的音樂播放器,重點(diǎn)在于使用服務(wù)來進(jìn)行音頻的播放控制與全局范圍的調(diào)用。

一、基本項(xiàng)目準(zhǔn)備:

考慮到音頻播放是個(gè)比較通用的服務(wù),決定將其創(chuàng)建為一個(gè)單獨(dú)的模塊AudioModule,并且在里面新增音頻服務(wù)主文件audio.service.ts,通用的音頻控制中心組件audio-studio.component.ts,作為輔助的TS接口文件play-data.model.ts與audio.model.ts。

最終項(xiàng)目音頻部分的目錄結(jié)構(gòu)如圖所示:

二、創(chuàng)建服務(wù):

ng2的服務(wù),照官網(wǎng)的說法來解釋,其實(shí)只是個(gè)帶有Injectable裝飾器的類而已,沒有其他任何特殊的定義,所以非常簡(jiǎn)單,不過定義如此簡(jiǎn)單的服務(wù)卻可以完成非常多酷炫的功能。

在TypeScript下定義變量有了public與private的訪問級(jí)區(qū)分,所以定義服務(wù)通常套路就是,定義服務(wù)內(nèi)使用的私有變量,在constructor構(gòu)造函數(shù)中進(jìn)行初始化操作,定義共有方法給服務(wù)的消費(fèi)者使用。

專注于音頻播放服務(wù)的場(chǎng)景,我們需要的私有變量有:

1.音頻對(duì)象

①用于通過JS進(jìn)行H5音頻的播放控制

2.播放列表數(shù)據(jù)

①服務(wù)內(nèi)部使用的播放列表概念,實(shí)際播放音頻時(shí)都是從此列表中播放音頻,服務(wù)的消費(fèi)者可以調(diào)用接口來操作此列表

3.正在播放音頻的參數(shù)

①音頻時(shí)長(zhǎng),當(dāng)前進(jìn)度以及播放模式(隨機(jī)播放之類)等

4.播放時(shí)的輪詢監(jiān)聽變量

①用于音頻播放過程中自動(dòng)啟動(dòng)輪詢,定時(shí)(每秒)更新播放參數(shù),當(dāng)音頻暫?;蛲V箷r(shí)取消此監(jiān)聽

服務(wù)初始化時(shí)需要做的事情有:

1.創(chuàng)建音頻對(duì)象

①可直接使用document.createElement('audio'),但不需要將其添加到DOM中。

②后續(xù)的播放控制均使用此對(duì)象來操作。

2.初始化私有變量

①私有變量中播放列表是一個(gè)數(shù)組,成員的參數(shù)使用audio.model.ts來規(guī)范化,

②必須包含一個(gè)Url參數(shù)存放播放源,以及其他可選參數(shù)

③相同的播放參數(shù)也用一個(gè)play-data.model.ts來規(guī)范化

3.給音頻添加onplay、onpause、onend等播放事件的監(jiān)聽

此服務(wù)提供的公有接口包括:

1. Toggle(audio)

①判斷傳入的音頻是否已在列表中,已存在則播放或暫停,若不存在則添加進(jìn)來并播放

2. Add()

①僅添加音頻到列表中

3. Remove()

①移除音頻出播放列表,需要考慮好移除后對(duì)播放隊(duì)列的影響,比如是否是正在播放的音頻被移除等等

4. Next()

5. Prev()

上一曲與下一曲操作,需要考慮到播放模式

6. Skip()

進(jìn)行播放進(jìn)度的跳轉(zhuǎn)

7. PlayList()

8. PlayData()

①用于暴露服務(wù)所維護(hù)的兩個(gè)數(shù)據(jù)(播放列表與播放參數(shù)),在指令中都是通過這兩個(gè)接口來呈現(xiàn)數(shù)據(jù)的

服務(wù)的完整代碼如下:

import { Injectable } from '@angular/core';
import { Audio } from './audio.model';
import { PlayData } from './play-data.model';

/**
 * 音頻服務(wù),只關(guān)心播放列表控制與進(jìn)度控制
 * 不提供組件支持,只提供列表控制方法接口及進(jìn)度控制接口
 */
@Injectable()
export class AudioService {
 // 主音頻標(biāo)簽
 private _audio: HTMLAudioElement;
 // 當(dāng)前列表中的音頻
 private playList: Audio[];
 // 當(dāng)前播放的數(shù)據(jù)
 private playData: PlayData;
 private listenInterval;
 /**
  * 創(chuàng)建新的音頻標(biāo)簽
  */
 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);
  }
 }

 /**
  * 移除列表中指定索引的音頻
  * 若移除的就是正在播放的音頻則自動(dòng)播放新的同索引音頻,不存在此索引則遞減
  * 若只剩這一條音頻了則停止播放并移除
  * @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('暫不考慮隨機(jī)播放將視為列表循環(huán)播放');
    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('暫不考慮隨機(jī)播放將視為列表循環(huán)播放');
    break;
   case 3:
    this._audio.currentTime = 0;
    break;
   default:
    if (this.playData.Index > 0) {
     this.playData.Index--;
     this.PlayIndex(this.playData.Index);
    }
    break;
  }
 }

 /**
  * 將當(dāng)前音頻跳轉(zhuǎn)到指定百分比進(jìn)度處
  * @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;
 }

 /**
  * 用于播放最后強(qiáng)行填滿進(jìn)度條
  * 防止播放進(jìn)度偏差導(dǎo)致的用戶體驗(yàn)
  */
 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');
  }
 }
}

三、使用服務(wù):

接下來要使用服務(wù)了,再ng2中服務(wù)也要依賴具體的模塊,我們得音頻服務(wù)依賴的就是自己的音頻模塊,在模塊的provider列表中配置它:

@NgModule({
 imports: [ CommonModule, SharedModule ],
 declarations: [ AudioStudioComponent ],
 exports: [ AudioStudioComponent ],
 providers: [ AudioService ]
})

接下來要實(shí)現(xiàn)服務(wù)的消費(fèi)者——AudioStudioComponent 了,步驟如下:

1.在構(gòu)造函數(shù)中注入服務(wù):

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方法添加的音頻如果是列表中僅有的一條音頻則會(huì)直接播放,所以如此添加兩條音頻會(huì)直接播放第一條音頻。

再在組件內(nèi)實(shí)現(xiàn)一個(gè)Skip方法用于進(jìn)度控制:

public Skip(e) {
  this.audio.Skip(e.layerX /
  document.getElementById('audio-total').getBoundingClientRect().width);
 }

現(xiàn)在運(yùn)行項(xiàng)目:

音頻播放器的樣式是崩塌的...因?yàn)檫@個(gè)組件是筆者另一個(gè)項(xiàng)目中直接copy過來了,在此demo項(xiàng)目中還沒加上移動(dòng)端rem適配,尷尬,不過大概的效果是展現(xiàn)出來了。 

完整項(xiàng)目代碼下載:angular2-demo_jb51.rar

四、總結(jié):

總的來說ng2的服務(wù)光使用來說難度不高,關(guān)鍵在于如何來完美發(fā)揮服務(wù)的特性,來做數(shù)據(jù)共享傳遞,以及封裝網(wǎng)絡(luò)請(qǐng)求等都是很好的選擇。另外本文沒有專門去講服務(wù)的一些問題點(diǎn),但使用服務(wù)還是有一些需要注意的地方的,比如只能在單個(gè)模塊中的provider中聲明,盡量保持全局單例,以及在懶加載模塊中會(huì)創(chuàng)建子注入器等,實(shí)際項(xiàng)目中還是要解決一些問題的。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 淺談angularJS2中的界面跳轉(zhuǎn)方法

    淺談angularJS2中的界面跳轉(zhuǎn)方法

    今天小編就為大家分享一篇淺談angularJS2中的界面跳轉(zhuǎn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-08-08
  • AngularJS國際化詳解及示例代碼

    AngularJS國際化詳解及示例代碼

    本文主要介紹AngularJS國際化的知識(shí),這里整理了相關(guān)資料和示例代碼以及實(shí)現(xiàn)效果圖,有興趣的小伙伴可以參考下
    2016-08-08
  • Angular Excel 導(dǎo)入與導(dǎo)出的實(shí)現(xiàn)代碼

    Angular Excel 導(dǎo)入與導(dǎo)出的實(shí)現(xiàn)代碼

    這篇文章主要介紹了Angular Excel 導(dǎo)入與導(dǎo)出的實(shí)現(xiàn)代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2019-04-04
  • 使用AngularJS制作一個(gè)簡(jiǎn)單的RSS閱讀器的教程

    使用AngularJS制作一個(gè)簡(jiǎn)單的RSS閱讀器的教程

    這篇文章主要介紹了使用Angular.js制作一個(gè)簡(jiǎn)單的RSS閱讀器的教程,AngularJS是一個(gè)非常有人氣的JavaScript庫,文中介紹的制作方法主要使用到了FreedReadR模版,需要的朋友可以參考下
    2015-06-06
  • Angular CLI 安裝和使用教程

    Angular CLI 安裝和使用教程

    本篇文章主要介紹了Angular CLI 安裝和使用教程,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-09-09
  • Angular2開發(fā)——組件規(guī)劃篇

    Angular2開發(fā)——組件規(guī)劃篇

    本文主要介紹了Angular2組件的相關(guān)知識(shí)。具有很好的參考價(jià)值,下面跟著小編一起來看下吧
    2017-03-03
  • 使用AngularJS對(duì)表單提交內(nèi)容進(jìn)行驗(yàn)證的操作方法

    使用AngularJS對(duì)表單提交內(nèi)容進(jìn)行驗(yàn)證的操作方法

    AngularJS是一款優(yōu)秀的前端JS框架,已經(jīng)被用于Google的多款產(chǎn)品當(dāng)中。下面通過本文給大家分享使用AngularJS對(duì)表單提交內(nèi)容進(jìn)行驗(yàn)證的操作方法,需要的的朋友參考下吧
    2017-07-07
  • 使用Angular 6創(chuàng)建各種動(dòng)畫效果的方法

    使用Angular 6創(chuàng)建各種動(dòng)畫效果的方法

    Angular能夠讓我們創(chuàng)建出具有原生表現(xiàn)效果的動(dòng)畫。我們將通過本文學(xué)習(xí)到如何使用Angular 6來創(chuàng)建各種動(dòng)畫效果。在此,我們將使用Visual Studio Code來進(jìn)行示例演示。感興趣的朋友跟隨小編一起看看吧
    2018-10-10
  • BootStrap+Angularjs+NgDialog實(shí)現(xiàn)模式對(duì)話框

    BootStrap+Angularjs+NgDialog實(shí)現(xiàn)模式對(duì)話框

    在完成一個(gè)后臺(tái)管理系統(tǒng)時(shí),需要用表格顯示注冊(cè)用戶的信息。但是用戶地址太長(zhǎng)了,不好顯示。所以想做一個(gè)模式對(duì)話框,點(diǎn)擊詳細(xì)地址按鈕時(shí),彈出對(duì)話框,顯示地址。下面小編給大家分享下實(shí)現(xiàn)方法,一起看下吧
    2016-08-08
  • Angular 多級(jí)路由實(shí)現(xiàn)登錄頁面跳轉(zhuǎn)(小白教程)

    Angular 多級(jí)路由實(shí)現(xiàn)登錄頁面跳轉(zhuǎn)(小白教程)

    這篇文章主要介紹了Angular 多級(jí)路由實(shí)現(xiàn)登錄頁面跳轉(zhuǎn)(小白教程),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11

最新評(píng)論