提问



我仔细阅读了关于这个主题的AngularJS文档,然后摆弄了一个指令。这就是小提琴。[94]


以下是一些相关的片段:



  • 来自HTML:


    <pane bi-title="title" title="{{title}}">{{text}}</pane>
    

  • 从窗格指令:


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



有几件事我不明白:



  • 为什么我必须'@''=''='一起使用"{{title}}"?

  • 我是否可以直接访问父作用域,而无需使用属性装饰我的元素?

  • 文档说通常需要通过表达式将数据从隔离范围传递到父范围,但这似乎也适用于双向绑定。为什么会这样做表达路线会更好吗?



我找到了另一个显示表达式解决方案的小提琴:http://jsfiddle.net/maxisam/QrCXh/[95]

最佳参考



  为什么我必须将{{title}}与 @ 一起使用,将title与=一起使用?



@ 将本地/指令范围属性绑定到已评估的DOM属性值。如果使用title=title1title="title1",则DOM属性title的值只是字符串title1。如果使用title="{{title}}",DOM属性title的值是{{title}}的插值,因此字符串将是父范围属性title当前设置的任何值。由于属性值始终是字符串,因此在使用 @ 时,您将始终在指令范围内以此属性的字符串值结束。


=将本地/指令范围属性绑定到父范围属性。因此,使用=,您可以使用父模型/范围属性名称作为DOM属性的值。你不能在=中使用{{}} s。


使用@,您可以执行title="{{title}} and then some" - {{title}}插值,然后将字符串和它们一些连接起来。最终的连接字符串是本地/指令范围属性获取的内容。 (你不能用=做这个,只有 @ 。)


使用 @ ,如果需要使用链接(ing)功能中的值,则需要使用attr.$observe('title', function(value) { ... })。例如,if(scope.title == "...")不会像你期望的那样工作。请注意,这意味着你只能异步访问这个属性。
如果你只使用模板中的值,则不需要使用$ observe()。例如,template: '<div>{{title}}</div>'[96]


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



  我是否还可以直接访问父作用域,而无需使用属性装饰我的元素?



是的,但仅当您不使用隔离范围时。从指令中删除此行


scope: { ... }


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



  文档说经常需要通过表达式将数据从隔离范围传递到父范围,但这似乎也适用于双向绑定。为什么表达式路由会更好?



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


也可以看看



  • Lukas的孤立范围博客文章(涵盖@,=,&)

  • dnc253对@和=
  • 的解释
  • 关于范围的类似博客的答案 - 指令部分(在摘要部分之前的底部)具有隔离范围及其父范围的图片 - 指令范围将@用于一个属性,将=用于另一个属性

  • &有什么区别? vs @和=在angularJS


其它参考1


这里有很多很好的答案,但我想提出我对@=&绑定之间的差异的观点,这对我来说是有用的。[97]]]


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



  

      
  1. @ 绑定用于传递字符串。
         这些字符串支持内插值的{{}}表达式。
         例如:
         。针对插值表达式进行评估
         指令的父范围。

  2.   
  3. =绑定用于双向模型绑定。父范围中的模型
         链接到指令隔离范围中的模型
         一个模型影响另一个,反之亦然。

  4.   
  5. & 绑定用于将方法传递到指令的范围,以便
         它可以在你的指令中调用。该方法是预先绑定的
         指令的父作用域,并支持参数。例如,如果方法是父作用域中的hello(name),则在
         为了从你的指令中执行方法,你必须
         叫$ scope.hello({name:world})

  6.   



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



  • @ 属性字符串绑定

  • = 双向模型绑定

  • & 回调方法绑定



符号还使得更清楚的是范围变量在指令实现中的含义:



  • @ string

  • = model

  • & 方法



为了有用(对我来说反正):



  1. =

  2. @

  3. &安培;


其它参考2


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


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


据我所知,<pane bi-title="{{title}}" title="{{title}}">{{text}}</pane>也应该有效。 bi-title将收到父范围变量值,该值可在指令中更改。


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

其它参考3


如果您想通过实例了解更多这方面的工作原理。 http://jsfiddle.net/juanmendez/k6chmnch/[101]


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: "<div><p>{{title1}} {{title2}}</p></div>"
    };
});

其它参考4


@ 获取字符串



  • 这不会创建任何绑定。你只是简单地将你传入的单词作为字符串



= 2路绑定



  • 从控制器进行的更改将反映在指令持有的引用中,反之亦然



&这个行为有点不同,因为范围得到一个函数返回传入的对象。我认为这是必要的,以使其发挥作用。小提琴应该明确这一点。



  • 调用此getter函数后,生成的对象的行为如下:


    • 如果传递函数:则在调用时在父(控制器)闭包中执行该函数

    • 如果传入非功能:只需获取没有绑定的对象的本地副本




点击
这个小提琴应该证明它们是如何工作的。在名称中get...特别注意范围功能,希望能更好地理解我的意思& [102]

其它参考5


指令中可以添加三种范围:



  1. 父作用域:这是默认作用域继承。



该指令及其父(其所在的控制器/指令)范围是相同的。
因此,对指令中的范围变量所做的任何更改也会反映在父控制器中。您不需要指定它,因为它是默认值。



  1. 子范围:指令创建一个子范围,如果您将指令的范围变量指定为true,则该范围将继承父范围。



在这里,如果更改指令内的范围变量,它将不会反映在父作用域中,但是如果更改作用域变量的属性,则反映在父作用域中,因为您实际修改了父作用域的作用域变量。


例,


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.
        }
    };
});



  1. 隔离范围:当您要创建不从控制器范围继承的范围时,可以使用此选项。



当您创建插件时会发生这种情况,因为这会使指令变为通用,因为它可以放在任何HTML中,并且不受其父作用域的影响。


现在,如果您不想与父作用域进行任何交互,那么您只需将作用域指定为空对象即可。


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


大多数情况并非如此,因为我们需要与父作用域进行一些交互,因此我们希望一些值/更改能够通过。
出于这个原因,我们使用:


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


@ 表示来自控制器范围的更改将反映在指令范围中,但如果修改指令范围中的值,则控制器范围变量不会受到影响。


@ always总是希望映射属性是一个表达式。这个非常重要;因为要使@前缀起作用,我们需要将属性值包装在{{}}中。


=是双向的,因此如果更改指令范围中的变量,控制器范围变量也会受到影响


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


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


例如,指令范围有一个变量dirVar,它与控制器范围的变量contVar同步。这为指令提供了大量的功能和概括,因为一个控制器可以与变量v1同步,而另一个使用相同指令的控制器可以要求dirVar与变量v2同步。


以下是使用示例:


指令和控制器是:


 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(注意@和=的不同):


<div my-directive
  class="directive"
  name="{{name}}"
  reverse="reverseName()"
  color="color" >
</div>


这是一个博客的链接,很好地描述了它。 [103]

其它参考6


我们可以使用: -



  1. @ : - 用于单向数据绑定的字符串值。在某种程度上,数据绑定只能将范围值传递给指令

  2. =: - 用于双向数据绑定的对象值。在双向数据绑定中,您可以更改指令中的范围值以及html中的范围值。

  3. & : - 用于方法和功能。



修改



Angular版本1.5 以及

组件定义中
有四种不同类型的绑定:



  1. = 双向数据绑定: - 如果我们更改了值,则会自动更新

  2. < 单向绑定: - 当我们只想从父作用域读取参数而不更新它时。

  3. @这适用于字符串参数

  4. &这是针对回调,以防您的组件需要向其父作用域输出内容


其它参考7


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


<!DOCTYPE html>
<html>
  <head>
    <title>Angular</title>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
  </head>
  <body ng-app="myApp">
    <div ng-controller="myCtrl as VM">
      <a my-dir
        attr1="VM.sayHi('Juan')" <!-- scope: "=" -->
        attr2="VM.sayHi('Juan')" <!-- scope: "@" -->
        attr3="VM.sayHi('Juan')" <!-- scope: "&" -->
      ></a>
    </div>
    <script>
    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"
        }
      }
    }]);
    </script>
  </body>
</html>

其它参考8


=方式为双向绑定,可让您在指令中进行实时更改。当某人将该变量更改为指令时,您将在指令中更改数据,但 @ 方式不是双向绑定。它的工作方式类似于文字。你绑定一次,你将只有它的价值。


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


AngularJS指令范围@和=[104]

其它参考9


@ local scope属性用于访问在指令外定义的字符串值。


=如果您需要在外部作用域和指令的隔离范围之间创建双向绑定,则可以使用=字符。


& local scope属性允许指令的使用者传入指令可以调用的函数。


请查看下面的链接,通过示例让您清楚地了解。我发现这非常有用,所以想分享它。


http://weblogs.asp.net/dwahlin/creating-custom-angularjs-directives-part-2-isolate-scope[105]

其它参考10


我在小提琴中实现了所有可能的选项。


它涉及所有选项:


scope:{
    name:'&'
},

scope:{
    name:'='
},

scope:{
    name:'@'
},

scope:{

},

scope:true,


https://jsfiddle.net/rishulmatta/v7xf2ujm[106]

其它参考11


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


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


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


我发现&的一个例子用于通过表达式将数据传递到隔离范围并传递到父范围的表示法,有用(并且不能使用双向数据绑定)是用于在ng-repeat内部呈现特殊数据结构的指令。


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


渲染的一部分是删除按钮,这里通过&附加来自外部范围的删除功能很有用。在render-directive里面看起来像


scope : { data = "=", deleteFunction = "&"},
template : "... <button ng-click = "deleteFunction()"></button>"


双向数据绑定,即data = "="不能使用,因为删除函数将在每个$digest周期运行,这是不好的,因为记录然后立即被删除并且从不呈现。

其它参考12


@=见其他答案。


关于 &
的一个问题
TL; DR; 结果
&从父级获取表达式(不仅像其他答案中的示例中的函数一样),并将其设置为调用表达式的指令中的函数。并且此函数能够通过传递带变量的对象来替换表达式的任何变量(甚至函数名称)。


解释结果
&是一个表达式引用,这意味着如果你传递类似的东西
<myDirective expr="x==y"></myDirective>,点击
在指令中,expr将是一个函数,它调用表达式,如:

function expr(){return x == y}。结果,
所以在指令s html <button ng-click="expr()"></button>中会调用表达式。在指令的js中,$scope.expr()也会调用表达式。

表达式将使用父目录的$ scope.x和$ scope.y调用。

您可以覆盖参数!

如果您通过电话设置,例如<button ng-click="expr({x:5})"></button>,点击
然后使用参数x和父参数y调用表达式
你可以覆盖它们
现在你知道了,为什么<button ng-click="functionFromParent({x:5})"></button>有用。

因为它只调用父表达式(例如<myDirective functionFromParent="function1(x)"></myDirective>)并用指定的参数替换可能的值,在本例中为x

它可能是:

<myDirective functionFromParent="function1(x) + 5"></myDirective>,点击
或点击
<myDirective functionFromParent="function1(x) + z"></myDirective>,点击
带着子的电话:

<button ng-click="functionFromParent({x:5, z: 4})"></button>。结果,
甚至功能替换:

<button ng-click="functionFromParent({function1: myfn, x:5, z: 4})"></button>


它只是一个表达式,如果它是一个函数,或许多函数,或只是比较,无关紧要。您可以替换此表达式的任何变量。


实施例结果
指令模板与被叫代码:

parent定义了$ scope.x,$ scope.y:

父模板:<myDirective expr="x==y"></myDirective>

<button ng-click="expr()"></button>调用$scope.x==$scope.y

<button ng-click="expr({x: 5})"></button>调用5 == $scope.y

<button ng-click="expr({x:5, y:6})"></button>电话5 == 6


parent定义了$ scope.function1,$ scope.x,$ scope.y:

父模板:<myDirective expr="function1(x) + y"></myDirective>


<button ng-click="expr()"></button>调用$scope.function1($scope.x) + $scope.y

<button ng-click="expr({x: 5})"></button>调用$scope.function1(5) + $scope.y

<button ng-click="expr({x:5, y:6})"></button>调用$scope.function1(5) + 6

指令将$ scope.myFn作为函数:

<button ng-click="expr({function1: myFn, x:5, y:6})"></button>电话$scope.myFn(5) + 6

其它参考13


他们之间的主要区别就是


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

其它参考14



  为什么我必须将{{title}}与@和title与=一起使用?



使用{{title}}时,只有父作用域值将传递给指令视图并进行评估。这仅限于一种方式,这意味着更改不会反映在父范围中。当您想要将子指令中所做的更改反映到父作用域时,可以使用=。这是双向的。



  我是否也可以直接访问父作用域,而无需装饰我的
  具有属性的元素?



当指令中包含scope属性(作用域:{})时,您将无法再直接访问父作用域。但仍然可以通过范围访问它。$ parent等。如果从指令中删除范围,可以直接访问它。



  文档说经常需要从中传递数据
  隔离范围通过表达式和父范围,但那
  似乎也可以使用双向绑定。为什么会这样
  表达路线会更好吗?



这取决于具体情况。如果要使用数据调用表达式或函数,可以使用&如果你想要共享数据,你可以使用=的二进制方式


您可以在以下链接中找到将数据传递到指令的多种方式之间的差异:


AngularJS - 隔离范围 - @ vs=vs& [107]


http://www.codeforeach.com/angularjs/angularjs-isolated-scopes-vs-vs[108]

其它参考15


@属性字符串绑定(单向)
=双向模型绑定
&安培;回调方法绑定

其它参考16


@将local/directive范围属性绑定到DOM属性的计算值。
=将本地/指令范围属性绑定到父范围属性。
&安培;绑定用于将方法传递到指令的范围,以便可以在指令中调用它。


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