zoukankan      html  css  js  c++  java
  • AngularJS中控制器之间通信方法

    在同个angular应用的控制器之间进行通信可以有很多种不同的方式,本文主要讲两种:

    基于scope继承的方式基于event传播的方式

    基于scope继承的方式

    最简单的让控制器之间进行通信的方法是通过scope的继承。假设有两个控制器Parent、Child,Child 在 Parent 内,那Child 可以称为子控制器,它将继承父控制器Parent的scope。这样,Child就可以访问到Parent的scope中的所有函数和变量了。
    需要注意的是,由于scope的继承也是基于Js的原型继承,如果变量是基本类型的,那在Child中的修改(写),有可能会导致Parent中的数据变脏。

    基本类型变量的继承

     1 function Sandcrawler($scope) {
     2     $scope.location = 'Mos Eisley North';
     3     $scope.move = function(newLocation) {
     4         $scope.location = newLocation;
     5     }
     6 }
     7 function Droid($scope) {
     8     $scope.sell = function(newLocation) {
     9         $scope.location = newLocation;
    10     }
    11 }
    12 // html
    13 <div ng-controller="Sandcrawler">
    14     <p>Location: </p>
    15     <button ng-click="move('Mos Eisley South')">Move</button>
    16     <div ng-controller="Droid">
    17         <p>Location: </p>
    18         <button ng-click="sell('Owen Farm')">Sell</button>
    19     </div>
    20 </div>

    看完上面的代码我们知道,location 属性是直接被注册到 $scope 中的,Droid控制器所拥有的scope从Sandcrawler控制器的scope中继承了这个属性并且可以读取它。看以下两个假设场景:

    • 如果 Sandcrawler 中改变了 location 属性,在 Droid 中也会读取到这个改变;在 view 中的表现则是:点击了Move 按钮的话,两个 p 标签都会显示 Mos Eisley South

    • 反过来,如果 Droid 中对 $scope.location 进行改写,它只改写自己scope中 location 属性的值,它不会影响 Sandcrawler 中的这个属性的值;在 view 中的表现则是:当点击了 Sell 按钮之后,两个控制器scope之间的数据共享就不复存在了,之后无论点多少次 Move 按钮,都影响不了 Droid 中的 p 标签的显示了

    经过上面的教训,有时候我们想要达到的效果可能达不到(如点了 Sell 按钮之后再点 Move 还想让它起作用),这样在ng的开发者中逐渐达成了一个一致的约定,千万不要把那些可以被子级scope改写的属性用基础类型直接添加在 $scope 对象上,而是应该尽可能地用对象类型去添加。

    对象类型变量的继承

    通过上面的结论我们知道,可以用对象类型的变量来作为属性添加到 $scope 中去,这样,只要是引用了这个对象的,无论是谁,在哪个控制器里面,对这个对象变量的改写都会影响都所有引用了这个对象的实例。看下面的代码:

     1 function Sandcrawler($scope) {
     2     $scope.sandcrawler.location = 'Mos Eisley North';
     3 }
     4 function Droid($scope) {
     5     $scope.summon = function(newLocation) {
     6         $scope.sandcrawler.location = newLocation;
     7     }
     8 }
     9 // html
    10 <div ng-controller="Sandcrawler">
    11     <p>Sandcrawler Location: </p>
    12     <div ng-controller="Droid">
    13         <button ng-click="summon('Owen Farm')">
    14             Summon Sandcrawler
    15         </button>
    16     </div>
    17 </div>

    跑一下上面的代码就知道,当我们使用“召唤术”的时候,可以改写 Sandcrawler 控制下的 p 标签的显示了。

    基于event传播的方式

    基于scope继承的方式只能处理父子级控制器之间的通信问题,不能处理兄弟/相邻控制器之间的通信问题。这时候,我们需要使用基于event传播的方式来进行通信,这里,ng为我们提供了三个方法:$on , $emit ,$broadcast ,需要明确的是:这种方法不仅可以处理兄弟scope间的通信问题,对于解决父子scope间的通信也是毫无压力。

    子-->父:$emit

    整个过程是这样的:

    • 子scope中的控制器通过 $scope.$emit 触发一个事件向上传播

    • 这个事件会经过每一层的父scope,至于处不处理是父scope自己的事情了

    • 如果处理,就在想要处理的那个祖先scope中放一个 $scope.$on 监听着就行了三四三

    •  1 // 父scope上的控制器
       2 function Sandcrawler($scope) {
       3     $scope.location = 'Mos Eisley North';
       4     $scope.$on('summon', function(e, newLocation) {
       5         $scope.location = newLocation;
       6     });
       7 }
       8 // 子scope上的控制器
       9 function Droid($scope) {
      10     $scope.location = 'Owen Farm';
      11     $scope.summon = function() {
      12         $scope.$emit('summon', $scope.location);
      13     }
      14 }
      15 // html
      16 <div ng-controller="Sandcrawler">
      17     <p>Sandcrawler Location: </p>
      18     <div ng-controller="Droid">
      19         <p>Droid Location: </p>
      20         <button ng-click="summon()">Summon Sandcrawler</button>
      21     </div>
      22 </div>

      如果你不想让你的事件再往更上层传播,在 $on 中的处理函数调用e.stopPropagation() 即可。

    父-->子:$broadcast

    从父到子,用另外一个方法就是了,同样用 $on 监听着,all done,看下面代码:

    // 父scope上的控制器
    function Sandcrawler($scope) {
        $scope.location = 'Mos Eisley North';
        $scope.recall = function() {
            $scope.$broadcast('recall', $scope.location);
        }
    }
    // 子scope上的控制器
    function Droid($scope) {
        $scope.location = 'Owen Farm';
        $scope.$on('recall', function(e, newLocation) {
            $scope.location = newLocation;
        });
    }
    // html
    <div ng-controller="Sandcrawler">
        <p>Sandcrawler Location: </p>
        <button ng-click="recall()">Recall Droids</button>
        <div ng-controller="Droid">
            <p>Droid Location: </p>
        </div>
    </div>

    同级之间

    拥有同个父scope的子级scope之间,也就是兄弟/相邻scope之间的通信,其实是借助“奶爸”传递消息的:

    • 子级scope中有谁想传消息了,$emit 一个给“奶爸”

    • 然后通过“奶爸” $broadcast 给所有孩子这个相同的信息,当然发出信息的那个可以选择是否要忽略掉自己发出的信息

     1 // 父scope上的控制器
     2 function Sandcrawler($scope) {
     3     $scope.$on('requestDroidRecall', function(e) {
     4         $scope.$broadcast('executeDroidRecall');
     5     });
     6 }
     7 // 子scope上的控制器
     8 function Droid($scope) {
     9     $scope.location = 'Owen Farm';
    10     $scope.recallAllDroids = function() {
    11         $scope.$emit('requestDroidRecall');
    12     }
    13     $scope.$on('executeDroidRecall', function() { 
    14         $scope.location = 'Sandcrawler';
    15     });
    16 }
    17 // html
    18 <div ng-controller="Sandcrawler">
    19     <div ng-controller="Droid">
    20         <h2>R2-D2</h2>
    21         <p>Droid Location: </p>
    22         <button ng-click="recallAddDroids()">Recall All Droids</button>
    23     </div>
    24     <div ng-controller="Droid">
    25         <h2>C-3PO</h2>
    26         <p>Droid Location: </p>
    27         <button ng-click="recallAddDroids()">Recall All Droids</button>
    28     </div>
    29 </div>

    上面代码中要注意的是:子scope通过 $emit 发出的事件名不能与父scope用 $broadcast 的事件名一样,如果有传参数,那当然参数可以一样,因为参数就是我们要传的数据。事件名不能一样是为了防止进入死循环。

  • 相关阅读:
    POJ
    巧得int(4字节)最大最小值
    POJ
    POJ
    2018牛客暑期多校训练第三场——C Shuffle Cards(rope大法)
    共享一些知识点的学习地址
    webstorm的各种快捷键配置
    Remote Debugging Chrome 结合Genymotion模拟器的移动端web真机调试
    支持新版chrome,用webstorm编译形成css和sourcemap,调试sass和less源文件
    最新版phonegap3.5.1环境搭建
  • 原文地址:https://www.cnblogs.com/xuepei/p/6022072.html
Copyright © 2011-2022 走看看