在AngularJS中,指令作用域中的”@”和”=”有什么区别?

What is the difference between '@' and '=' in directive scope in AngularJS?

我已经仔细阅读了关于这个主题的AngularJS文档,然后胡乱摆弄了一个指令。这是小提琴。

下面是一些相关的片段:

  • 从HTML:

    1
    <pane bi-title="title" title="{{title}}">{{text}}</pane>
  • 从pane指令:

    1
    scope: { biTitle: '=', title: '@', bar: '=' },

有几件事我不明白:

  • 为什么我要用"{{title}}"'@'以及"title"'='呢?
  • 我还可以直接访问父作用域,而不需要用属性来修饰我的元素吗?
  • 文档中说,"通常希望通过表达式将数据从独立作用域传递到父作用域",但对于双向绑定来说,这似乎也很好。为什么表达路径会更好?

我还找到了另一个显示表达式解决方案的工具:http://jsfiddle.net/maxisam/qrcxhxh/


Why do I have to use"{{title}}" with '@' and"title" with '='?

@将本地/指令作用域属性绑定到dom属性的计算值。如果使用title=title1title="title1",dom属性"title"的值只是字符串title1。如果使用title="{{title}}",则dom属性"title"的值是{{title}}的插值值,因此字符串将是当前设置为的父范围属性"title"的值。由于属性值始终是字符串,因此在使用@时,您将始终在指令的作用域中使用该属性的字符串值。

=将本地/指令作用域属性绑定到父作用域属性。因此,使用=,可以使用父模型/作用域属性名称作为dom属性的值。不能将{{}}s与=一起使用。

使用@,您可以执行诸如title="{{title}} and then some"--的操作,然后将字符串"and them some"与它连接起来。最后连接的字符串是本地/指令作用域属性所得到的字符串。(不能用=,只能@进行此操作。)

使用@时,如果需要使用链接函数中的值,则需要使用attr.$observe('title', function(value) { ... })。例如,if(scope.title =="...")不会像您预期的那样工作。注意,这意味着您只能异步访问这个属性。如果只使用模板中的值,则不需要使用$observer()。例如,template: '{{title}}'

使用=,您不需要使用$observe。

Can I also access the parent scope directly, without decorating my element with an attribute?

是的,但前提是不使用隔离范围。从指令中删除此行

scope: { ... }

然后您的指令将不会创建新的作用域。它将使用父作用域。然后可以直接访问所有父作用域属性。

The documentation says"Often it's desirable to pass data from the isolated scope via an expression and to the parent scope", but that seems to work fine with bidirectional binding too. Why would the expression route be better?

是的,双向绑定允许本地/指令作用域和父作用域共享数据。"表达式绑定"允许指令调用由dom属性定义的表达式(或函数),您还可以将数据作为参数传递给表达式或函数。因此,如果您不需要与父级共享数据——您只想调用在父级作用域中定义的函数——您可以使用&;语法。

也见

  • 卢卡斯的独立范围博客帖子(封面@,=,&;)
  • DNC253对@and的解释=
  • 关于作用域,我的博客式回答——指令部分(在底部,在摘要部分之前)有一个独立作用域及其父作用域的图片——指令作用域对一个属性使用@,对另一个属性使用=。
  • 在AngularJS中,&vs@and=


这里有很多很好的答案,但我想就证明对我有用的@=&绑定之间的差异提出我的看法。

这三个绑定都是通过元素的属性将数据从父作用域传递到指令的独立作用域的方法:

  • @ binding is for passing strings.
    These strings support {{}} expressions for interpolated values.
    For example:
    . The interpolated expression is evaluated against
    directive's parent scope.

  • = binding is for two-way model binding. The model in parent scope
    is linked to the model in the directive's isolated scope. Changes to
    one model affects the other, and vice versa.

  • & binding is for passing a method into your directive's scope so that
    it can be called within your directive. The method is pre-bound to
    the directive's parent scope, and supports arguments. For example if the method is hello(name) in parent scope, then in
    order to execute the method from inside your directive, you must
    call $scope.hello({name:'world'})

  • 我发现,通过使用较短的描述来引用范围绑定,更容易记住这些差异:

    • @属性字符串绑定
    • =双向模型绑定
    • &回调方法绑定

    这些符号还使指令实现中作用域变量所代表的内容更加清晰:

    • @
    • =
    • &

    为了有用(无论如何对我来说):

  • =
  • @
  • 和;

  • =表示双向绑定,因此是对父范围变量的引用。这意味着,当您更改指令中的变量时,它也将在父范围中更改。

    @表示变量将被复制(克隆)到指令中。

    据我所知,{{text}}也应该起作用。bi-title将接收父范围变量值,该值可以在指令中更改。

    如果需要更改父作用域中的多个变量,可以从指令内对父作用域执行函数(或通过服务传递数据)。


    If you would like to see more how this work with a live example. http://jsfiddle.net/juanmendez/k6chmnch/

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    var app = angular.module('app', []);
    app.controller("myController", function ($scope) {
        $scope.title ="binding";
    });
    app.directive("jmFind", function () {
        return {
            replace: true,
            restrict: 'C',
            transclude: true,
            scope: {
                title1:"=",
                title2:"@"
            },
            template:"<p>
    {{title1}} {{title2}}
    </p>"
        };
    });


    @get as字符串

    • 这不会创建任何绑定。你只是把你传进来的单词当作一个字符串

    =2路装订

    • 控制器所做的更改将反映在指令持有的参考中,反之亦然。

    &的行为稍有不同,因为作用域得到一个函数,返回传入的对象。我想这是必要的。小提琴手应该说清楚。

    • 调用此getter函数后,结果对象的行为如下:
      • 如果传递了一个函数:那么当调用时,该函数将在父(控制器)闭包中执行。
      • 如果传入了非函数:只需获取没有绑定的对象的本地副本

    这把小提琴应该演示它们是如何工作的。特别注意名称中带有get...的范围函数,希望更好地理解我对&的意思。


    指令中有三种添加范围的方法:

  • 父作用域:这是默认作用域继承。
  • 指令和它的父(控制器/指令)作用域相同。因此,对指令内的作用域变量所做的任何更改也会反映在父控制器中。您不需要指定它,因为它是默认的。

  • 子作用域:如果将指令的作用域变量指定为true,则指令将创建从父作用域继承的子作用域。
  • 在这里,如果您更改指令内的作用域变量,它不会反映在父作用域中,但是如果您更改作用域变量的属性,即反映在父作用域中,正如您实际修改了父作用域变量一样。

    例子,

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    app.directive("myDirective", function(){

        return {
            restrict:"EA",
            scope: true,
            link: function(element, scope, attrs){
                scope.somvar ="new value"; //doesnot reflect in the parent scope
                scope.someObj.someProp ="new value"; //reflects as someObj is of parent, we modified that but did not override.
            }
        };
    });
  • 独立作用域:当要创建不从控制器作用域继承的作用域时,使用此选项。
  • 当您创建插件时会发生这种情况,因为这使指令成为通用的,因为它可以放在任何HTML中,并且不受其父作用域的影响。

    现在,如果您不希望与父作用域进行任何交互,那么您可以将作用域指定为空对象。像,

    1
    scope: {} //this does not interact with the parent scope in any way

    大多数情况下,情况并非如此,因为我们需要与父范围进行一些交互,因此我们希望传递一些值/更改。因此,我们使用:

    1
    2
    3
    1."@"   (  Text binding / one-way binding )
    2."="   ( Direct model binding / two-way binding )
    3."&"   ( Behaviour binding / Method binding  )

    @意味着来自控制器作用域的更改将反映在指令作用域中,但如果修改指令作用域中的值,则控制器作用域变量不会受到影响。

    @始终要求映射的属性是表达式。这非常重要;因为要使"@"前缀起作用,我们需要将属性值包装在内。

    =是双向的,因此如果在指令作用域中更改变量,控制器作用域变量也会受到影响。

    &;用于绑定控制器范围方法,以便在需要时可以从指令调用它

    这里的优点是变量名在控制器范围和指令范围内不必相同。

    例如,指令作用域有一个变量"dirvar",它与控制器作用域的变量"contvar"同步。这为指令提供了很多功能和泛化,因为一个控制器可以与变量v1同步,而另一个使用相同指令的控制器可以要求dirvar与变量v2同步。

    以下是使用示例:

    指令和控制器是:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
     var app = angular.module("app", []);
     app.controller("MainCtrl", function( $scope ){
        $scope.name ="Harry";
        $scope.color ="#333333";
        $scope.reverseName = function(){
         $scope.name = $scope.name.split("").reverse().join("");
        };
        $scope.randomColor = function(){
            $scope.color = '#'+Math.floor(Math.random()*16777215).toString(16);
        };
    });
    app.directive("myDirective", function(){
        return {
            restrict:"EA",
            scope: {
                name:"@",
                color:"=",
                reverse:"&"
            },
            link: function(element, scope, attrs){
               //do something like
               $scope.reverse();
              //calling the controllers function
            }
        };
    });

    以及HTML(注意@和=)的区别:

    1
    2
    3
    4
    5
    <div my-directive
      class="directive"
      name="{{name}}"
      reverse="reverseName()"
      color="color">

    这是一个很好地描述它的博客链接。


    简单来说,我们可以使用:

  • @:-用于单向数据绑定的字符串值。在单向数据绑定中,只能将作用域值传递给指令

  • =:-用于双向数据绑定的对象值。通过双向数据绑定,您可以在指令和HTML中更改作用域值。

  • &;:-用于方法和函数。

  • 编辑

    在我们的角版本1.5及以上的组件定义中有四种不同类型的绑定:

  • =双向数据绑定:如果我们更改值,它会自动更新
  • <单向绑定:当我们只想从父作用域中读取参数而不更新它时。

  • @这是字符串参数

  • &这是用于回调,以防您的组件需要将某些内容输出到其父范围。


  • 我创建了一个包含角代码的小HTML文件,演示了它们之间的区别:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    <!DOCTYPE html>
    <html>
      <head>
        Angular
        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js">
      </head>
      <body ng-app="myApp">
       
          <a my-dir
            attr1="VM.sayHi('Juan')" <!-- scope:"=" -->
            attr2="VM.sayHi('Juan')" <!-- scope:"@" -->
            attr3="VM.sayHi('Juan')" <!-- scope:"&" -->
          >
       
       
        angular.module("myApp", [])
        .controller("myCtrl", [function(){
          var vm = this;
          vm.sayHi = function(name){
            return ("Hey there," + name);
          }
        }])
        .directive("myDir", [function(){
          return {
            scope: {
              attr1:"=",
              attr2:"@",
              attr3:"&"
            },
            link: function(scope){
              console.log(scope.attr1);   // =, logs"Hey there, Juan"
              console.log(scope.attr2);   // @, logs"VM.sayHi('Juan')"
              console.log(scope.attr3);   // &, logs"function (a){return h(c,a)}"
              console.log(scope.attr3()); // &, logs"Hey there, Juan"
            }
          }
        }]);
       
      </body>
    </html>

    =way是双向绑定,它允许您在指令中进行实时更改。当有人从指令中更改该变量时,您将在指令中更改数据,但@way不是双向绑定。它像文本一样工作。您绑定一次,就只有它的值。

    为了更清楚地了解它,您可以使用这篇伟大的文章:

    AngularJS指令作用域"@"和"="


    即使范围是本地的,例如在您的示例中,您也可以通过属性$parent访问父范围。在下面的代码中,假设title是在父作用域上定义的。然后您可以访问标题为$parent.title

    1
    2
    link : function(scope) { console.log(scope.$parent.title) },
    template :"the parent has the title {{$parent.title}}"

    但是,在大多数情况下,使用属性可以更好地获得相同的效果。

    例如,我在一个指令中找到了"&;notation",它用于"通过表达式将数据从独立作用域传递到父作用域",该指令用于在ng repeat中呈现特殊的数据结构。

    1
    <render data ="record" deleteFunction ="dataList.splice($index,1)" ng-repeat ="record in dataList"> </render>

    渲染的一部分是"删除"按钮,在这里,通过&;从外部作用域附加DeleteFunction非常有用。在render指令中,它看起来像

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    scope : { data ="=", deleteFunction ="&
    <hr><P>@本地作用域属性用于访问在指令外部定义的字符串值。</P><P>=如果需要在外部作用域和指令的隔离作用域之间创建双向绑定,可以使用=字符。</P><P>&本地作用域属性允许指令的使用者传入指令可以调用的函数。</P><P>请查看下面的链接,通过例子让您清楚地了解它。我发现它非常有用,所以想分享一下。</P><P>http://weblogs.asp.net/dwahlin/creating-custom-angularjs-directives-part-2-isolate-scope</P><p><center>[wp_ad_camp_3]</center></p><hr><P>我在一把小提琴上实现了所有可能的选择。</P><P>它处理所有选项:</P>[cc]scope:{
        name:'&'
    },

    scope:{
        name:'='
    },

    scope:{
        name:'@'
    },

    scope:{

    },

    scope:true,

    https://jsfiddle.net/rishulmatta/v7xf2ujm


    正是在他们之间的主要差分 </P >

    1
    2
    3
    @ Attribute string binding
    = Two-way model binding
    & Callback method binding

    这个问题已经被打得死去活来了,但无论如何,我还是会分享这个问题,以防外面的其他人正在与安古拉吉斯望远镜的可怕混乱斗争。这将包括=<@&::。完整的报告可以在这里找到。

    =建立了双向绑定。更改父级中的属性将导致子级的更改,反之亦然。

    <建立了一个单向绑定,父-子。更改父属性将导致子属性发生更改,但更改子属性不会影响父属性。

    @将为子属性分配标记属性的字符串值。如果属性包含表达式,则每当表达式的计算结果不同时,子属性都会更新。例如:

    1
    <child-component description="The movie title is {{$ctrl.movie.title}}" />
    1
    2
    3
    bindings: {
        description: '@',
    }

    这里,子作用域中的description属性将是表达式"The movie title is {{$ctrl.movie.title}}"的当前值,其中movie是父作用域中的对象。

    &有点棘手,实际上似乎没有令人信服的理由使用它。它允许您计算父范围中的表达式,用子范围中的变量替换参数。示例(plunk):

    1
    2
    3
    <child-component
      foo ="myVar + $ctrl.parentVar + myOtherVar"
    </child-component>
    1
    2
    3
    4
    5
    6
    angular.module('heroApp').component('childComponent', {
      template:"{{  $ctrl.parentFoo({myVar:5, myOtherVar:'xyz'})  }}",
      bindings: {
        parentFoo: '&foo'
      }
    });

    给定parentVar=10时,parentFoo({myVar:5, myOtherVar:'xyz'})的表达式将对5 + 10 + 'xyz'进行计算,该分量将表现为:

    1
    15xyz

    您希望何时使用这种复杂的功能?&通常被人们用来向子作用域传递父作用域中的回调函数。然而,在现实中,通过使用"<"传递函数也可以达到同样的效果,这更为简单,并且避免了用大括号语法传递参数({myVar:5, myOtherVar:'xyz'})。考虑:

    使用&回调:

    1
    <child-component parent-foo="$ctrl.foo(bar)"/>
    1
    2
    3
    4
    5
    6
    angular.module('heroApp').component('childComponent', {
      template: '<button ng-click="$ctrl.parentFoo({bar:'xyz'})">Call foo in parent</button>',
      bindings: {
        parentFoo: '&'
      }
    });

    使用<回调:

    1
    <child-component parent-foo="$ctrl.foo"/>
    1
    2
    3
    4
    5
    6
    angular.module('heroApp').component('childComponent', {
      template: '<button ng-click="$ctrl.parentFoo('xyz')">Call foo in parent</button>',
      bindings: {
        parentFoo: '<'
      }
    });

    请注意,对象(和数组)是通过引用传递给子作用域的,而不是复制的。这意味着,即使它是单向绑定,您也在父范围和子范围内使用相同的对象。

    要查看不同的前缀的作用,请打开此plunk。

    使用::进行一次性绑定(初始化)

    [官方文件]较新版本的AngularJS引入了一个一次性绑定的选项,其中子作用域属性只更新一次。这通过消除监视父属性的需要来提高性能。语法与上述不同;要声明一次性绑定,可以在component标记中的表达式前面添加::

    1
    2
    3
    <child-component
      tagline ="::$ctrl.tagline">
    </child-component>

    这将把EDOCX1的值(21)传播到子作用域,而不建立单向或双向绑定。注:如果tagline最初是undefined在父作用域中,angular将监视它直到它改变,然后一次性更新子作用域中的相应属性。

    总结

    下表显示了前缀的工作方式,具体取决于属性是否为对象、数组、字符串等。

    How the various isolate scope bindings work


    这是@=解答的。 </P >

    知道了一个关于& 热释光;医生; 有&expression(不算例在其他功能的类只在解答)从一个父集,和它作为一个功能的指令,这是calls的表达。这一功能的能力和资格的任何变量(to replace甚至function name of expression),由一passing面向变量的动力学研究。 </P >

    explained 在这一&表情的参考,如果你的护照的某类均值 expr指令,这将是一个功能,那就是calls的表达,如: function expr(){return x == y}。 所以在指令的HTML 将调用的表达。在JS调用的指令是$scope.expr()威尔带来的表达。 会叫的表达与scope.x scope.y美元和美元的父母。 你要在今天的覆盖能力的参数。 如果你用他们的集调用,如 那么"expression参数会被与你的父母的yx和参数。 你可以覆盖两人。 现在你知道为什么厂。 正是因为它的父母calls expression of(如)和replaces尽可能与你的specified参数的值,在本案例x。 它可能是: 与孩子的调用: 。 或甚至与功能的替代: 。 </P >

    它是表达的不安,有物或如果它是一个多功能的,或是函数的比较。你可以和任何变量本replace函数表达。 </P >

    例子: 指令模板和应用代码: 父母有定义的scope.x美元,美元的scope.y: 父母模板: calls $scope.x==$scope.y calls 5 == $scope.y calls 5 == 6 </P >

    父母有定义的scope.function1 scope.x美元,美元,美元的scope.y: 父母模板: </P >

    calls $scope.function1($scope.x) + $scope.y calls $scope.function1(5) + $scope.y calls $scope.function1(5) + 6 指令有scope.myfn美元作为功能: calls $scope.myFn(5) + 6 </P >


    Why do I have to use"{{title}}" with '@' and"title" with '='?

    当你使用{ } { title的值的范围,只会对父母的指令和evaluated passed景。这是公司对意义的变化将是一路,不在父母reflected是息息相关的。你可以用"="当你想reflect的子女对父母的指令完成的变迁也息息相关。这是双路。 </P >

    Can I also access the parent scope directly, without decorating my
    element with an attribute?

    当它的指令有属性的范围(范围:{ }),然后你可以长到好的父母会directly接入范围。但它仍然对它尽可能接入通过美元的范围。如果你的父母,remove等。范围从指令,它不能被accessed directly。 </P >

    The documentation says"Often it's desirable to pass data from the
    isolated scope via an expression and to the parent scope", but that
    seems to work fine with bidirectional binding too. Why would the
    expression route be better?

    它是一个基于depends的背景。如果你想调用的表达或功能与数据平安,你使用&;和如果你想共享数据,你可以使用biderectional方式运用"=" </P >

    你可以找到的数据之间的差异的方法对多部passing指令在下面的链接: </P >

    angularjs––V = V"离体scopes &; </P >

    http:/ / / / www.codeforeach.com angularjs angularjs -对-对离体scopes </P >


    属性的字符串的结合"(单程) =二路模型的结合 方法结合callback &; </P >


    "binds A /指令范围的局部性质对evaluated DOM属性的值。 binds = A /指令范围的局部性质,到了一个父母的财产范围。 &;结合的一种方法是用passing入你的指令的范围,所以它不能被应用在你的指令。 </P >

    属性的字符串"的结合 =二路模型的结合 方法结合callback &; </P >