最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解AngularJS的通信機(jī)制

 更新時(shí)間:2015年06月18日 11:27:41   投稿:goldensun  
這篇文章主要介紹了AngularJS的通信機(jī)制,AngularJS是非常具有人氣的JavaScript庫,需要的朋友可以參考下

現(xiàn)在幾乎滿世界的人都在問! 外面有人么? 這里是 USS AngularJS, 我們遇到麻煩了,我們的服務(wù)講得是克靈貢語(Klingon) 而我們的控制器不能同它們的Ferengi 指令通信了. 有人能幫助我們么!

我已經(jīng)不知道有多少次遇到這種有關(guān)什么才是AngularJS里面的組件通信的最佳方式這樣的問題了. 很多時(shí)候答案都會(huì)是為此使用 $rootScope 對(duì)象去向任何想要收聽的人廣播$broadcast出一條消息. 然而,那還真不是做這件事的最佳方式. 組件之間廣播消息意味著它們需要多少知道一些其它組件編碼的細(xì)節(jié),這樣就限制了它們的模塊化和重用.

本文我就將展示如何為AngularJS中的內(nèi)部組件通信使用發(fā)布/訂閱模式.


AngularJS 有多種方式可供你用于組件之間的通信,而最常使用的方法卻需要你知道太多有關(guān)那些組件如何通信的細(xì)節(jié),這樣就增加了組件之間的耦合度,并降低了它們的模塊性和內(nèi)聚程度. 這樣也就使得你的組件很難在其它應(yīng)用程序中重用.

通過使用發(fā)布/訂閱設(shè)計(jì)模式,我們可以降低組件之間的耦合度,并將它們的之間通信的細(xì)節(jié)封裝起來. 這將能幫助增加你組件的模塊化程度,可測(cè)試性以及可重用性.

我將會(huì)描述的發(fā)布/訂閱模式實(shí)現(xiàn)由 Eric Burley, @eburley 在它的帖子angularjs.org 觀察, 有關(guān)發(fā)布訂閱模式.. 中推薦過。

我所描述的示例應(yīng)用程序,會(huì)向你展示你可以將發(fā)布/訂閱模式如何運(yùn)用于內(nèi)部控制器通信以及控制器的服務(wù)通信. 你可以在GitHub上我的資源庫 angularjs-pubsub 下面找到源代碼.
 
首先我們需要一條通信管道

首先我們來講講用于處理發(fā)布和訂閱信息的服務(wù)。我定義了一個(gè)服務(wù)接口,提供了發(fā)布和訂閱信息的方法,我們可以用它來處理我們想要用來交換的信息。

在下面的代碼中,我定義了兩個(gè)內(nèi)部信息; _EDIT_DATA_, 用來表示我們需要編輯跟隨信息傳過來的數(shù)據(jù),和 _DATA_UPDATED_, 用來表示我們的數(shù)據(jù)已經(jīng)被改變。這些都是定義在內(nèi)部的,用戶沒辦法訪問到它們的,這樣有助于隱藏具體實(shí)現(xiàn)。

而對(duì)于每條信息,有兩個(gè)方法; 一個(gè)用來發(fā)布信息推送給訂閱者,另一個(gè)可以讓訂閱者注冊(cè)一個(gè)回調(diào)方法,當(dāng)接收到信息的時(shí)候,這個(gè)方法就會(huì)被調(diào)用。


用來向訂閱者發(fā)布信息方法是 editData,在第 9 行,還有 dataUpated,在第 19 行。它們通過 $rootScope.$broadcast 方法向待處理事件推送私有通知。

用來注冊(cè)事件的方法,通過 $scope.$on 建立監(jiān)聽,當(dāng)接收到廣播的消息之后,就會(huì)輪流執(zhí)行那些被訂閱者注冊(cè)到服務(wù)上的事件。同時(shí),由于訂閱者需要自己的 scope 作為參數(shù)傳過來,我們可以用它來執(zhí)行監(jiān)聽的信息,從而避免了維護(hù)監(jiān)聽者列表這些復(fù)雜的處理。注冊(cè)事件的方法是 onEditData,在 13 行,還有 onDataUpdated 在 23 行。

為了隱藏實(shí)現(xiàn)細(xì)節(jié),我用了 Revealing Module (揭示模塊:好丑的名字)模式,只返回那些我希望讓用戶使用的方法。
 

angular.module(['application.services'])
  // define the request notification channel for the pub/sub service
  .factory('requestNotificationChannel', ['$rootScope', function ($rootScope) {
    // private notification messages
    var _EDIT_DATA_ = '_EDIT_DATA_';
    var _DATA_UPDATED_ = '_DATA_UPDATED_';
 
    // publish edit data notification
    var editData = function (item) {
      $rootScope.$broadcast(_EDIT_DATA_, {item: item});
    };
    //subscribe to edit data notification
    var onEditData = function($scope, handler) {
      $scope.$on(_EDIT_DATA_, function(event, args) {
        handler(args.item);
      });
    };
    // publish data changed notification
    var dataUpdated = function () {
      $rootScope.$broadcast(_DATA_UPDATED_);
    };
    // subscribe to data changed notification
    var onDataUpdated = function ($scope, handler) {
      $scope.$on(_DATA_UPDATED_, function (event) {
        handler();
      });
    };
    // return the publicly accessible methods
    return {
      editData: editData,
      onEditData: onEditData,
      dataUpdated: dataUpdated,
      onDataUpdated: onDataUpdated
    };
  }])

發(fā)布消息

發(fā)布消息很簡單,首先我們需要在我們的控制器里為 requestNotificationChannel 引入一些依賴. 你可以在下面dataService的定義第二行看到這個(gè). 當(dāng)事件發(fā)生時(shí),如果需要向需要了解有變化發(fā)生的其它對(duì)象發(fā)送信號(hào), 你只需要調(diào)用requestNotificationChannel上恰當(dāng)?shù)耐ㄖ椒ň涂梢粤? 如果你注意到了dataService的 saveHop, deleteHop 和 addHop 方法, 你就會(huì)看到它們都調(diào)用了 requestNotificationChannel 上的dataUpdated方法, 這個(gè)方法將會(huì)給偵聽器發(fā)送信號(hào),偵聽器則已經(jīng)用 onDataUpdated 方法注冊(cè)過了.

  // define the data service that manages the data
  .factory('dataService', ['requestNotificationChannel', function (requestNotificationChannel) {
    // private data
    var hops = [
      { "_id": { "$oid": "50ae677361d118e3646d7d6c"}, "Name": "Admiral", "Origin": "United Kingdom", "Alpha": 14.75, "Amount": 0.0, "Use": "Boil", "Time": 0.0, "Notes": "Bittering hops derived from Wye Challenger. Good high-alpha bittering hops. Use for: Ales Aroma: Primarily for bittering Substitutions: Target, Northdown, Challenger", "Type": "Bittering", "Form": "Pellet", "Beta": 5.6, "HSI": 15.0, "Humulene": 0.0, "Caryophyllene": 0.0, "Cohumulone": 0.0, "Myrcene": 0.0, "Substitutes": ""} ,
      { "_id": { "$oid": "50ae677361d118e3646d7d6d"}, "Name": "Ahtanum", "Origin": "U.S.", "Alpha": 6.0, "Amount": 0.0, "Use": "Boil", "Time": 0.0, "Notes": "Distinctive aromatic hops with moderate bittering power from Washington. Use for: Distinctive aroma Substitutes: N/A", "Type": "Aroma", "Form": "Pellet", "Beta": 5.25, "HSI": 30.0, "Humulene": 0.0, "Caryophyllene": 0.0, "Cohumulone": 0.0, "Myrcene": 0.0, "Substitutes": ""} ,
      { "_id": { "$oid": "50ae677361d118e3646d7d6e"}, "Name": "Amarillo Gold", "Origin": "U.S.", "Alpha": 8.5, "Amount": 0.0, "Use": "Boil", "Time": 0.0, "Notes": "Unknown origin, but character similar to Cascade. Use for: IPAs, Ales Aroma: Citrus, Flowery Substitutions: Cascade, Centennial", "Type": "Aroma", "Form": "Pellet", "Beta": 6.0, "HSI": 25.0, "Humulene": 0.0, "Caryophyllene": 0.0, "Cohumulone": 0.0, "Myrcene": 0.0, "Substitutes": ""} ,
      { "_id": { "$oid": "50ae677361d118e3646d7d6f"}, "Name": "Aquila", "Origin": "U.S.", "Alpha": 6.5, "Amount": 0.0, "Use": "Boil", "Time": 0.0, "Notes": "Aroma hops developed in 1988. Limited use due to high cohumolone.Used for: Aroma hops Substitutes: ClusterNo longer commercially grown.", "Type": "Aroma", "Form": "Pellet", "Beta": 3.0, "HSI": 35.0, "Humulene": 0.0, "Caryophyllene": 0.0, "Cohumulone": 0.0, "Myrcene": 0.0, "Substitutes": ""} ,
      { "_id": { "$oid": "50ae677361d118e3646d7d70"}, "Name": "Auscha (Saaz)", "Origin": "Czech Republic", "Alpha": 3.3, "Amount": 0.0, "Use": "Boil", "Time": 0.0, "Notes": " Use for: Pilsners and Bohemian style lagers Aroma: Delicate, mild, clean, somewhat floral -- Noble hops Substitute: Tettnanger, LublinExamples: Pulsner Urquell", "Type": "Aroma", "Form": "Pellet", "Beta": 3.5, "HSI": 42.0, "Humulene": 0.0, "Caryophyllene": 0.0, "Cohumulone": 0.0, "Myrcene": 0.0, "Substitutes": ""} ,
    ];
    // sends notification that data has been updated
    var saveHop = function(hop) {
      requestNotificationChannel.dataUpdated();
    };
    // removes the item from the array and sends a notification that data has been updated
    var deleteHop = function(hop) {
      for(var i = 0; i < hops.length; i++) {
        if(hops[i]._id.$oid === hop._id.$oid) {
          hops.splice(i, 1);
          requestNotificationChannel.dataUpdated();
          return;
        }
      };
    };
    // internal function to generate a random number guid generation
    var S4 = function() {
      return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
    };
    // generates a guid for adding items to array
    var guid = function () {
     return (S4() + S4() + "-" + S4() + "-4" + S4().substr(0,3) + "-" + S4() + "-" + S4() + S4() + S4()).toLowerCase();
    };
    // function to add a hop to the array and sends a notification that data has been updated
    var addHop = function(hop) {
      hops.id.$oid = guid();
      hops.push(hop);
      requestNotificationChannel.dataUpdated();
    };
    // returns the array of hops
    var getHops = function() {
      return hops;
    };
    // returns a specific hop with the given id
    var getHop = function(id) {
      for(var i = 0; i < hops.length; i++) {
        if(hops[i]._id.$oid === id) {
          return hops[i];
        }
      };
    };
    // return the publicly accessible methods
    return {
      getHops: getHops,
      getHop: getHop,
      saveHop: saveHop,
      deleteHop: deleteHop,
      addHop: addHop
    }
  }]);

 
接收事件通知

從 requestNotificationChannel 接收事件通知也很簡單,額外的我們只需要回調(diào)處理器來在消息被發(fā)送時(shí)使用通知來做一些自己的處理. 我們將再次需要添加一些依賴到面向我們的控制器、服務(wù)以及指令的 requestNotificationChannel 上, 你可以在下面代碼的第二行中看到這些. 接下來我們需要定義一個(gè)事件回調(diào)處理器來對(duì)事件通知做出回應(yīng),你可以在下面的第五行代碼中看到. 然后我們需要通過調(diào)用 onDataUpdated 方法來吧我們的回調(diào)處理器注冊(cè)到requestNotificationChannel,并傳入來自控制器和回調(diào)處理器的范圍, 我們?cè)诘?行代碼中做了這些事情.

 

  //define the controller for view1
  .controller('view1-controller', ['$scope', 'dataService', 'requestNotificationChannel', function($scope, dataService, requestNotificationChannel) {
    $scope.hops = dataService.getHops();
 
    var onDataUpdatedHandler = function() {
      $scope.hops = dataService.getHops();
    }
 
    requestNotificationChannel.onDataUpdated($scope, onDataUpdatedHandler);
 
    $scope.onEdit = function(hop) {
      requestNotificationChannel.editData(hop);
    }
 
    $scope.onDelete = function(hop) {
      dataService.deleteHop(hop);
    }
  }]);

用于控制器通信的控制器

我們也可以將 the requestNotificationChannel 用于控制器間的通信. 我們只需要有一個(gè)控制器扮演發(fā)布者的角色,而另外一個(gè)控制器扮演訂閱者的角色就行了. 如果你觀察到前段代碼第11行view1-controller的onEdit方法,你會(huì)看到它發(fā)送了一個(gè)editData消息,消息包含需要使用 requestNotificationChannel 編輯的項(xiàng).  下面的 view2-controller 從第5行到第9行將它的 onEditDataHandler 用 requestNotificationChannel 進(jìn)行了注冊(cè). 如此無論何時(shí)view1-controller一旦發(fā)送editData消息,帶上要修改的項(xiàng),view2-controller都會(huì)受到editData消息的通知,獲得該項(xiàng)并將其更新到它的模型.
 

  //define the controller for view1
  .controller('view2-controller', ['$scope', 'dataService', 'requestNotificationChannel', function($scope, dataService, requestNotificationChannel) {
    $scope.hop = null;
 
    var onEditDataHandler = function(item) {
      $scope.hop = item;
    };
 
    requestNotificationChannel.onEditData($scope, onEditDataHandler);
 
    $scope.onSave = function() {
      dataService.saveHop($scope.hop);
      $scope.hop = null;
    }
 
    $scope.onCancel = function() {
      $scope.hop = null;
    }
  }]);

寫一個(gè)好的接口文檔

有一件事情可能會(huì)被忽略,我們?cè)诮M件間用了通信接口,而這些接口,它們需要一個(gè)好的文檔來說明應(yīng)當(dāng)如何使用。上面的例子中,如果沒有文檔,用戶肯定不會(huì)知道 onEditData 會(huì)給回調(diào)函數(shù)傳一個(gè)待編輯數(shù)據(jù)。所以當(dāng)你開始用這個(gè)模式,用好的技巧在于,給方法寫注釋文檔,以確保通知服務(wù)明確知道發(fā)生了什么事情。
總結(jié)

好了,我們探討了如何在你的 AngularJS 應(yīng)用中使用訂閱/發(fā)布模式來實(shí)現(xiàn)模塊間通信。該模式可以讓你的模塊從內(nèi)部消息解耦,更便于復(fù)用。你甚至可以把模塊之間的通信全部替換成訂閱/發(fā)布模式。尤其當(dāng)你的服務(wù)中有很多異步請(qǐng)求,以及你希望把數(shù)據(jù)緩存在服務(wù)中,從而減少和服務(wù)器通信的時(shí)候,這種模式相當(dāng)有效。

我希望這對(duì)你有所幫助,你可以在我的 GitHub 倉庫 angularjs-pubsub 下找到例子的代碼。

相關(guān)文章

  • Angular通過指令動(dòng)態(tài)添加組件問題

    Angular通過指令動(dòng)態(tài)添加組件問題

    這篇文章主要介紹了Angular通過指令動(dòng)態(tài)添加組件問題,文中通過寫一個(gè)小組件來簡單總結(jié)下,需要的朋友可以參考下
    2018-07-07
  • AngularJS中filter的使用實(shí)例詳解

    AngularJS中filter的使用實(shí)例詳解

    這篇文章主要介紹了AngularJS中filter的使用實(shí)例詳解的相關(guān)資料,這里提供實(shí)例幫助大家理解掌握,希望能幫助到大家,需要的朋友可以參考下
    2017-08-08
  • AngularJs動(dòng)態(tài)加載模塊和依賴注入詳解

    AngularJs動(dòng)態(tài)加載模塊和依賴注入詳解

    這篇文章主要為大家介紹了AngularJs動(dòng)態(tài)加載模塊和依賴注入,感興趣的小伙伴們可以參考一下
    2016-01-01
  • 詳解Angular依賴注入

    詳解Angular依賴注入

    依賴注入(DI -- Dependency Injection)是一種重要的應(yīng)用設(shè)計(jì)模式。Angular里面也有自己的DI框架,在設(shè)計(jì)應(yīng)用時(shí)經(jīng)常會(huì)用到它,它可以我們的開發(fā)效率和模塊化程度。&#160;Angular系統(tǒng)中通過在類上添加@Injectable裝飾器來告訴系統(tǒng)這個(gè)類(服務(wù))是可注入的。
    2021-05-05
  • 實(shí)例解析angularjs的filter過濾器

    實(shí)例解析angularjs的filter過濾器

    本文對(duì)angularjs的filter過濾器進(jìn)行系統(tǒng)介紹,附上實(shí)例解析,便于理解。具有很好的參考價(jià)值,需要的朋友可以看下
    2016-12-12
  • 詳解JavaScript的AngularJS框架中的作用域與數(shù)據(jù)綁定

    詳解JavaScript的AngularJS框架中的作用域與數(shù)據(jù)綁定

    這篇文章主要介紹了JavaScript的AngularJS框架中的作用域與數(shù)據(jù)綁定,包括作用域的繼承以及數(shù)據(jù)的單向和雙向綁定等重要知識(shí)點(diǎn),需要的朋友可以參考下
    2016-03-03
  • 使用ngView配合AngularJS應(yīng)用實(shí)現(xiàn)動(dòng)畫效果的方法

    使用ngView配合AngularJS應(yīng)用實(shí)現(xiàn)動(dòng)畫效果的方法

    這篇文章主要介紹了使用ngView配合AngularJS應(yīng)用實(shí)現(xiàn)動(dòng)畫效果的方法,AngularJS是十分熱門的JavaScript庫,需要的朋友可以參考下
    2015-06-06
  • 小談angular ng deploy的實(shí)現(xiàn)

    小談angular ng deploy的實(shí)現(xiàn)

    這篇文章主要介紹了小談angular ng deploy的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • AngularJS實(shí)現(xiàn)根據(jù)不同條件顯示不同控件

    AngularJS實(shí)現(xiàn)根據(jù)不同條件顯示不同控件

    本篇文章主要介紹了AngularJS實(shí)現(xiàn)根據(jù)不同條件顯示不同控件的相關(guān)知識(shí)。具有很好的參考價(jià)值。下面跟著小編一起來看下吧
    2017-04-04
  • Angular 2父子組件數(shù)據(jù)傳遞之@Input和@Output詳解(下)

    Angular 2父子組件數(shù)據(jù)傳遞之@Input和@Output詳解(下)

    這篇文章主要給大家介紹了關(guān)于Angular 2父子組件數(shù)據(jù)傳遞之@Input和@Output的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧。
    2017-07-07

最新評(píng)論

枞阳县| 滨州市| 桂东县| 保德县| 仁化县| 东平县| 寻乌县| 尖扎县| 涡阳县| 崇阳县| 龙泉市| 长泰县| 九台市| 奈曼旗| 文登市| 通化县| 金平| 将乐县| 丘北县| 阿鲁科尔沁旗| 星子县| 磴口县| 都昌县| 寻甸| 尼勒克县| 阿巴嘎旗| 宁强县| 威信县| 青铜峡市| 泾阳县| 浪卡子县| 文登市| 双峰县| 洛川县| 隆子县| 郯城县| 合阳县| 左贡县| 马龙县| 顺昌县| 泰宁县|