中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何使用services完成音頻播放器應用開發

發布時間:2021-10-29 17:45:52 來源:億速云 閱讀:126 作者:柒染 欄目:編程語言

如何使用services完成音頻播放器應用開發,針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。

我們來討論services,整理我們的代碼并完成我們的音頻播放器應用。

通過這整個系列的教程,我們會開發一個NPR(美國全國公共廣播電臺)廣播的音頻播放器,它能顯示Morning Edition節目里現在播出的最新故事,并在我們的瀏覽器里播放。完成版的Demo可以看看這里。

目前為止,我們把注意力都放在了如何把視圖綁定到$scope和如何用controller管理數據,從內存和效率角度出 發,controllers僅當需要的時候才會被實例化并在不需要的時候被丟棄掉,這就意味著每一次我們使用route跳轉或者重載視圖,當前的controller會被銷毀。

Services可以讓我們在整個應用的生命周期中保存數據并且可以讓controllers之間共享數據。

第六部分:Services

Services都是單例的,就是說在一個應用中,每一個Serice對象只會被實例化一次(用$injector服務),主要負責提供一個接口把 特定函數需要的方法放在一起,我們就拿上一章見過的$http  Service來舉例,他就提供了訪問底層瀏覽器的XMLHttpRequest對象的方法,相較于調用底層的XMLHttpRequest對 象,$http API使用起來相當的簡單。

Angular內建了很多服務供我們日常使用,這些服務對于在復雜應用中建立自己的Services都是相當有用的。

AngularJS讓我們可以輕松的創建自己的services,僅僅注冊service即可,一旦注冊,Angular編譯器就可以找到并加載他作為依賴供程序運行時使用,

最常見的創建方法就是用angular.module API 的factory模式

angular.module('myApp.services', [])   .factory('githubService', function() {     var serviceInstance = {};     // 我們的第一個服務     return serviceInstance;   });

當然,我們也可以使用內建的$provide service來創建service。

這個服務并沒有做實際的事情,但是他向我們展示了如何去定義一個service。創建一個service就是簡單的返回一個函數,這個函數返回一個對象。這個對象是在創建應用實例的時候創建的(記住,這個對象是單例對象)

我們可以在這個縱貫整個應用的單例對象里處理特定的需求,在上面的例子中,我們開始創建了GitHub service,

接下來讓我們添加一些有實際意義的代碼去調用GitHub的API:

angular.module('myApp.services', [])   .factory('githubService', ['$http', function($http) {       var doRequest = function(username, path) {       return $http({         method: 'JSONP',         url: 'https://api.github.com/users/' + username + '/' + path + '?callback=JSON_CALLBACK'       });     }     return {       events: function(username) { return doRequest(username, 'events'); },     };   }]);

我們創建了一個只有一個方法的GitHub  Service,events可以獲取到給定的GitHub用戶最新的GitHub事件,為了把這個服務添加到我們的controller中。我們建立一 個controller并加載(或者注入)githubService作為運行時依賴,我們把service的名字作為參數傳遞給controller  函數(使用中括號[])

app.controller('ServiceController', ['$scope', 'githubService',     function($scope, githubService) { }]);

請注意,這種依賴注入的寫法對于js壓縮是安全的,我們會在以后的章節中深入導論這件事情。

我們的githubService注入到我們的ServiceController后,我們就可以像使用其他服務(我們前面提到的$http服務)一樣的使用githubService了。

我們來修改一下我們的示例代碼,對于我們視圖中給出的GitHub用戶名,調用GitHub API,就像我們在數據綁定第三章節看到的,我們綁定username屬性到視圖中

<div ng-controller="ServiceController">   <label for="username">Type in a GitHub username</label>   <input type="text" ng-model="username" placeholder="Enter a GitHub username, like auser" />   <pre ng-show="username">{{ events }}</pre> </div>

現在我們可以監視 $scope.username屬性,基于雙向數據綁定,只要我們修改了視圖,對應的model數據也會修改

app.controller('ServiceController', ['$scope', 'githubService',     function($scope, githubService) {     // Watch for changes on the username property.     // If there is a change, run the function     $scope.$watch('username', function(newUsername) {             // uses the $http service to call the GitHub API             // and returns the resulting promise       githubService.events(newUsername)         .success(function(data, status, headers) {                     // the success function wraps the response in data                     // so we need to call data.data to fetch the raw data           $scope.events = data.data;         })     }); }]);

因為返回了$http promise(像我們上一章一樣),我們可以像直接調用$http service一樣的去調用.success方法

如何使用services完成音頻播放器應用開發

(示例截圖,請前往原文測試)

在這個示例中,我們注意到輸入框內容改變前有一些延遲,如果我們不設置延遲,那么我們就會對鍵入輸入框的每一個字符調用GitHub API,這并不是我們想要的,我們可以使用內建的$timeout服務來實現這種延遲。

如果想使用$timeout服務,我們只要簡單的把他注入到我們的githubService中就可以了

app.controller('ServiceController', ['$scope', '$timeout', 'githubService',     function($scope, $timeout, githubService) { }]);

注意我們要遵守Angular services依賴注入的規范:自定義的service要寫在內建的Angular services之后,自定義的service之間是沒有先后順序的。

我們現在就可以使用$timeout服務了,在本例中,在輸入框內容的改變間隔如果沒有超過350毫秒,$timeout  service不會發送任何網絡請求。換句話說,如果在鍵盤輸入時超過350毫秒,我們就假定用戶已經完成輸入,我們就可以開始向GitHub發送請求

app.controller('ServiceController', ['$scope', '$timeout', 'githubService',   function($scope, $timeout, githubService) {     // The same example as above, plus the $timeout service     var timeout;     $scope.$watch('username', function(newVal) {       if (newVal) {         if (timeout) $timeout.cancel(timeout);         timeout = $timeout(function() {           githubService.events(newVal)           .success(function(data, status) {             $scope.events = data.data;           });         }, 350);       }     });   }]);

從這應用開始,我們只看到了Services是如何把簡單的功能整合在一起,Services還可以在多個controllers之間共享數據。比 如,如果我們的應用有一個設置頁面供用戶設置他們的GitHub  username,那么我們就要需要把username與其他controllers共享。

這個系列的最后一章我們會討論路由以及如何在多頁面中跳轉。

為了在controllers之間共享username,我們需要在service中存儲username,記住,在應用的生命周期中Service是一直存在的,所以可以把username安全的存儲在這里

angular.module('myApp.services', [])   .factory('githubService', ['$http', function($http) {     var githubUsername;     var doRequest = function(path) {       return $http({         method: 'JSONP',         url: 'https://api.github.com/users/' + githubUsername + '/' + path + '?callback=JSON_CALLBACK'       });     }     return {       events: function() { return doRequest('events'); },       setUsername: function(newUsername) { githubUsername = newUsername; }     };   }]);

現在,我們的service中有了setUsername方法,方便我們設置GitHub用戶名,在應用的任何controller中,我們都可以調用events()方法,而根本不用操心在scope對象中的username設置是否正確。

我們應用里的Services

在我們的應用里,我們需要為3個元素創建對應的服務:audio元素,player元素,nprService。最簡單的就是audio  service,切記,不要在controller中有任何的操控DOM的行為,如果這么做會污染你的controller并留下潛在的隱患。

在我們的應用中,PlayerController中有一個audio element元素的實例

app.controller('PlayerController', ['$scope', '$http',   function($scope, $http) {   var audio = document.createElement('audio');   $scope.audio = audio;   // ...

我們可以建立一個單例audio service,而不是在controller中設置audio元素

app.factory('audio', ['$document', function($document) {   var audio = $document[0].createElement('audio');   return audio; }]);

注意:我們使用了另一個內建服務$document服務,這個服務就是window.document元素(所有html頁面里javascript的根對象)的引用。

現在,在我們的PlayController中我們可以引用這個audio元素,而不是在controller中建立這個audio元素

app.controller('PlayerController', ['$scope', '$http', 'audio',   function($scope, $http, audio) {   $scope.audio = audio;

盡管看起來我們并沒有增強代碼的功能或者讓代碼更加清晰,但是如果有一天,PlayerController不再需要audio service了,我們只需要簡單刪除這個依賴就可以了。到那個時候你就能切身體會到這種代碼寫法的妙處了!

注意:現在我們可以在其他應用中共享audio service了,因為他并沒有綁定特定于本應用的功能

為了看到效果,我們來建立下一個服務: player  service,在我們的當前循環中,我們附加了play()和stop()方法到PlayController中。這些方法只跟playing  audio有關,所以并沒有必要綁定到PlayController,總之,使用PlayController調用player service  API來操作播放器,而并不需要知道操作細節是最好不過的了。

讓我們來創建player service,我們需要注入我們剛剛創建的還熱乎的audio service 到 player service

app.factory('player', ['audio', function(audio) {   var player = {};   return player; }]);

現在我們可以把原先定義在PlayerController中play()方法挪到player service中了,我們還需要添加stop方法并存儲播放器狀態。

  1. app.factory('player', ['audio', function(audio) { 

  2.   var player = { 

  3.     playing: false, 

  4.     current: null, 

  5.     ready: false, 

  6.   

  7.     play: function(program) { 

  8.       // If we are playing, stop the current playback 

  9.       if (player.playing) player.stop(); 

  10.       var url = program.audio[0].format.mp4.$text; // from the npr API 

  11.       player.current = program; // Store the current program 

  12.       audio.src = url; 

  13.       audio.play(); // Start playback of the url 

  14.       player.playing = true 

  15.     }, 

  16.   

  17.     stop: function() { 

  18.       if (player.playing) { 

  19.         audio.pause(); // stop playback 

  20.         // Clear the state of the player 

  21.         playerplayer.ready = player.playing = false; 

  22.         player.current = null; 

  23.       } 

  24.     } 

  25.   }; 

  26.   return player; 

  27. }]);

現在我們已經擁有功能完善的play() and stop()方法,我們不需要使用PlayerController來管理跟播放相關的操作,只需要把控制權交給PlayController里的player service即可

app.controller('PlayerController', ['$scope', 'player',   function($scope, player) {   $scope.player = player; }]);

如何使用services完成音頻播放器應用開發

(注:示例截圖,請到原文測試)

注意:使用player service的時候,我們不需要去考慮audio service,因為player會幫我們處理audio service。

注意:當audio播放結束,我們沒有重置播放器的狀態,播放器會認為他自己一直在播放

為了解決這個問題,我們需要使用$rootScope服務(另一個Angular的內建服務)來捕獲audio元素的ended事件,我們注入$rootScope服務并創建audio元素的事件監聽器

app.factory('player', ['audio', '$rootScope',   function(audio, $rootScope) {   var player = {     playing: false,     ready: true,     // ...   };   audio.addEventListener('ended', function() {     $rootScope.$apply(player.stop());   });   return player; }]);

在這種情況下,為了需要捕獲事件而使用了$rootScope service,注意我們調用了$rootScope.$apply()。 因為ended事件會觸發外圍Angular event loop.我們會在后續的文章中討論event loop。

最后,我們可以獲取當前播放節目的詳細信息,比如,我們創建一個方法獲取當前事件和當前audio的播放間隔(我們會用這個參數顯示當前的播放進度)。

app.factory('player', ['audio', '$rootScope',   function(audio, $rootScope) {   var player = {     playing: false,     // ...     currentTime: function() {       return audio.currentTime;     },     currentDuration: function() {       return parseInt(audio.duration);     }   }   };   return player; }]);

在audio元素中存在timeupdate事件,我們可以根據這個事件更新播放進度

audio.addEventListener('timeupdate', function(evt) {     $rootScope.$apply(function() {       playerplayer.progress = player.currentTime();       playerplayer.progress_percent = player.progress / player.currentDuration();     });   });

最后,我們一個添加canplay事件來表示視圖中的audio是否準備就緒

app.factory('player', ['audio', '$rootScope',   function(audio, $rootScope) {   var player = {     playing: false,     ready: false,     // ...   }   audio.addEventListener('canplay', function(evt) {     $rootScope.$apply(function() {       player.ready = true;     });   });   return player; }]);

現在,我們有了player service,我們需要操作nprLink directive 來讓播放器 &rsquo;play&rsquo;,而不是用$scope(注意,這么做是可選的,我們也可以在PlayerController中創建play()和stop()方法)

在directive中,我們需要引用本地scope的player,代碼如下:

app.directive('nprLink', function() {   return {     restrict: 'EA',     require: ['^ngModel'],     replace: true,     scope: {       ngModel: '=',       player: '='     },     templateUrl: '/code/views/nprListItem',     link: function(scope, ele, attr) {       scopescope.duration = scope.ngModel.audio[0].duration.$text;     }   } });

現在,為了跟我們已有的模板整合,我們需要更新 index.html的npr-link調用方式

<npr-link ng-model="program" player="player"></npr-link>

在視圖界面,我們調用play.play(ngModel),而不是play(ngModel).

<div class="nprLink row" player="player" ng-click="player.play(ngModel)">   <span class="name large-8 columns">     <button class="large-2 small-2 playButton columns" ng-click="ngModel.play(ngModel)"><div class="triangle"></div></button>     <div class="large-10 small-10 columns">       <div class="row">         <span class="large-12">{{ ngModel.title.$text }}</span>       </div>       <div class="row">         <div class="small-1 columns"></div>         <div class="small-2 columns push-8"><a href="{{ ngModel.link[0].$text }}">Link</a></div>       </div>     </div>   </span> </div>

邏輯上,我們需要添加播放器視圖到總體視圖上,因為我們可以封裝player數據和狀態。查看playerView directive 和 template。

我們來創建最后一個service,nprService,這個service很像 githubService,我們用$http service來獲取NPR的最新節目

app.factory('nprService', ['$http', function($http) {     var doRequest = function(apiKey) {       return $http({         method: 'JSONP',         url: nprUrl + '&apiKey=' + apiKey + '&callback=JSON_CALLBACK'       });     }       return {       programs: function(apiKey) { return doRequest(apiKey); }     };   }]);

在PlayerController,我們調用nprService的programs()(調用$http service)

app.controller('PlayerController', ['$scope', 'nprService', 'player',   function($scope, nprService, player) {   $scope.player = player;   nprService.programs(apiKey)     .success(function(data, status) {       $scope.programs = data.list.story;     }); }]);

我們建議使用promises來簡化API,但是為了展示的目的,我們在下一個post會簡單介紹promises。

當PlayerController初始化后,我們的nprService會獲取最新節目,這樣我們在nprService  service中就成功封裝了獲取NPR節目的功能。另外,我們添加RelatedController在側邊欄顯示當前播放節目的相關內容。當我們的 player service中獲取到最新節目時,我們將$watc這個player.current屬性并顯示跟這個屬性相關的內容。

app.controller('RelatedController', ['$scope', 'player',   function($scope, player) {   $scope.player = player;     $scope.$watch('player.current', function(program) {     if (program) {       $scope.related = [];       angular.forEach(program.relatedLink, function(link) {         $scope.related.push({           link: link.link[0].$text,           caption: link.caption.$text         });       });     }   }); }]);

在 HTML 代碼中, we just reference the related links like we did with our NPR programs, using the ng-repeat directive:

<div class="large-4 small-4 columns" ng-controller="RelatedController">   <h3>Related content</h3>   <ul id="related">     <li ng-repeat="s in related"><a href="{{ s.link }}">{{ s.caption }}</a></li>   </ul> </div>

只要player.current內容改變,顯示的相關內容也會改變。

在下一章也是我們的“AngularJS &ndash; 七步從菜鳥到專家”的最后一章,我們會討論依賴注入,路由,和產品級別工具來讓我們更快的使用AngularJS

要將這個代碼庫保存到本地,請先確保安裝了git,clone此代碼庫,然后check out其中的part6分支:

git clone https://github.com/auser/ng-newsletter-beginner-series.git git checkout -b part6 ./bin/server.sh

關于如何使用services完成音頻播放器應用開發問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

蕉岭县| 安义县| 全椒县| 滁州市| 无棣县| 五原县| 玛曲县| 永新县| 原平市| 乐都县| 湾仔区| 开化县| 张家界市| 灵石县| 响水县| 贺州市| 鄂托克旗| 武汉市| 巩留县| 芷江| 广平县| 肇州县| 宣恩县| 宁海县| 桦甸市| 靖宇县| 民勤县| 类乌齐县| 大宁县| 平乡县| 建始县| 尚志市| 甘洛县| 卢湾区| 荔波县| 石狮市| 昌宁县| 淳化县| 大悟县| 临高县| 曲沃县|