AngularJS的指令范围中'@'和'='有什么区别?

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

这里有一些相关的片段:

  • 从HTML:

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

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

有几件事我没有得到:

  • 为什么我必须用"{{title}}" '@'"title"'=' "title"一起使用"{{title}}"
  • 我也可以直接访问父范围,而不用装饰我的元素的属性?
  • 该文件说“通常是希望通过expression式和父范围从隔离的范围传递数据” ,但是这似乎也适用于双向绑定。 为什么expression路线会更好?

我发现另一个小提琴也显示expression式解决scheme: http : //jsfiddle.net/maxisam/QrCXh/

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

@将本地/指令范围属性绑定到DOM属性评估值 。 如果使用title=title1title="title1" ,则DOM属性“title”的值就是stringtitle1 。 如果使用title="{{title}}" ,那么DOM属性“title”的值就是{{title}}的内插值,因此该string将是当前设置的任何父范围属性“title”。 由于属性值始终是string,所以在使用@时,您将始终在该指令的作用域中为该属性结束一个string值。

=将本地/指令范围属性绑定到父级范围属性 。 因此,对于= ,您使用父级模型/范围属性名称作为DOM属性的值。 您不能使用带有=的 {{}}

有了@,你可以做title="{{title}} and then some" ,然后插入title="{{title}} and then some" – {{title}”,然后string“and them some”与它连接。 最后的连接string是local / directive作用域属性的值。 (你不能用=来做,只有@)

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

= ,你不需要使用$观察。

我也可以直接访问父范围,而不用装饰我的元素的属性?

是的,但只有当你不使用隔离范围。 从你的指令中删除这一行

scope: { ... }

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

该文件说“通常是希望通过expression式和父范围从隔离的范围传递数据”,但是这似乎也适用于双向绑定。 为什么expression路线会更好?

是的,双向绑定允许本地/指导作用域和父作用域共享数据。 “expression式绑定”允许指令调用由DOM属性定义的expression式(或函数) – 您也可以将数据作为parameter passing给expression式或函数。 因此,如果您不需要与父级共享数据 – 只需要调用在父级范围中定义的函数 – 您可以使用语法。

也可以看看

  • 卢卡斯的孤立范围博客文章 (涵盖@,=,&)
  • dnc253对@和= 的解释
  • 我关于作用域的类似博客的回答 – 指令部分(在摘要部分之前的底部的方式)具有隔离作用域及其父作用域的图片 – 指令作用域对一个属性使用@和对另一个属性使用=
  • 在angularJS中,&vs @和=有什么区别?

这里有很多很好的答案,但是我想提供我对@=和绑定之间差异的看法,这对我来说是有用的。

所有这三种绑定都是通过元素的属性将数据从父范围传递到指令的隔离范围的方法:

  1. @绑定是为了传递string。 这些string支持插值的{{}}expression式。 例如: 。 内插expression式是根据指令的父范围进行评估的。

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

  3. binding是将一个方法传入你的指令的作用域,以便它可以在你的指令中被调用。 该方法预先绑定到指令的父范围,并支持参数。 例如,如果方法在父范围中是hello(name),那么为了从指令中执行该方法,必须调用$ scope.hello({name:'world'})

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

  • @ 属性string绑定
  • = 双向模型绑定
  • & callback方法绑定

这些符号也使得它更清晰地说明了scopevariables在你的指令实现中所代表的内容:

  • @ string
  • = 型号
  • & 方法

为了有用(反正我):

  1. =
  2. @

=表示双向绑定,所以引用父范围的variables。 这意味着,当您更改指令中的variables时,它也将在父范围中更改。

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

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

如果您需要更改父范围中的多个variables,则可以从指令中对父范围执行函数(或通过服务传递数据)。

如果您想了解更多如何使用现场示例工作。 http://jsfiddle.net/juanmendez/k6chmnch/

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

@ 得到string

  • 这不会产生任何约束力。 你只是简单地把你传入的单词作为string

= 2路绑定

  • 控制人所做的更改将反映在指令所持的参考文献中,反之亦然

这个行为有点不同,因为范围得到一个返回传入的对象的函数。 我假设这是必要的,使其工作。 小提琴应该清楚这一点。

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

这小提琴应该演示他们如何工作 。 要特别注意范围函数的名称,以get...希望更好地理解我的意思是什么&

可以在指令中添加三种方法:

  1. 父范围 :这是默认范围inheritance。

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

  1. 如果将指令的作用域variables指定为true,则子作用域 :指令将创build一个从父作用域inheritance的子作用域。

在这里,如果更改指令中的范围variables,它不会反映在父范围中,但是如果更改了范围variables的属性,这反映在父范围中,因为您实际上修改了父范围的范围variables。

例,

 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. 隔离范围 :当您想要创build不从控制器范围inheritance的范围时使用此范围。

在创build插件时会发生这种情况,因为这会使指令成为通用的,因为它可以放置在任何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 ) 

@表示来自控制器作用域的更改将反映在指令作用域中,但如果修改指令作用域中的值,则控制器作用域variables将不受影响。

@总是期望映射的属性是一个expression式。 这个非常重要; 因为要使“@”前缀工作,我们需要将属性值封装在{{}}中。

=是双向的,所以如果你改变指令范围中的variables,控制器范围variables也会受到影响

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

这里的优点是variables的名称在控制器范围和指令范围中不需要相同。

例如,指令作用域有一个variables“dirVar”,它与控制器作用域的variables“contVar”同步。 由于一个控制器可以与variablesv1同步,而另一个使用相同指令的控制器可以要求dirVar与variablesv2同步,所以这赋予了指令许多的力量和概括性。

下面是使用的例子:

指令和控制器是:

  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> 

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

只要我们可以使用: –

  1. @ : – 用于单向数据绑定的string值。 在一种数据绑定方式中,您只能将范围值传递给指令

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

  3. : – 用于方法和function。

编辑

在我们的Angular版本1.5以上的组件定义中
有四种不同types的绑定:

  1. = 双向数据绑定 : – 如果我们更改了值,它会自动更新
  2. < 单向绑定 : – 当我们只想从父范围读取一个参数而不更新它时。

  3. @这是用于string参数

  4. &这是为了callback ,以防您的组件需要输出一些东西到它的父范围

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

https://gist.github.com/RobertAKARobin/a02426c375596f0bef89

 <!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')" attr2="VM.sayHi('Juan')" attr3="VM.sayHi('Juan')"></a> </div> <script> angular.module("myApp", []) .controller("myCtrl", [function(){ var vm = this; vm.sayHi = function(name){ return ("Hey there, " + name); } }]) .directive("myDir", [function(){ var directive = { 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" } } return directive; }]); </script> </body> </html> 

=方式是双向绑定 ,可以让您在指令中进行实时更改。 当有人改变这个variables的指令,你会有改变你的指令内的数据,但@方式不是双向绑定 。 它像文本一样工作。 你绑定一次,你将只有它的价值。

为了更清楚地理解,你可以使用这个伟大的文章:

AngularJS指令范围'@'和'='

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

=在需要在外部作用域和指令的隔离范围之间创build双向绑定的情况下,可以使用=字符。

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

请检查下面的链接,让你清楚地了解与例子。我发现它真的非常有用,所以想到分享它。

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

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

它处理所有选项:

 scope:{ name:'&' }, scope:{ name:'=' }, scope:{ name:'@' }, scope:{ }, scope:true, 

https://jsfiddle.net/rishulmatta/v7xf2ujm

即使当范围是本地的,就像在你的例子中,你可以通过属性$parent来访问父范围。 假设在下面的代码中,该title在父范围上定义。 您可以以$parent.title访问标题:

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

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

我find了一个“&”符号的例子,它用于“通过expression式向父范围传递数据,有用(双向数据绑定无法使用)”用于在ng-repeat中呈现特殊的数据结构。

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

渲染的一部分是一个删除button,在这里通过&附加一个从外部范围删除function是有用的。 在render-directive里面看起来像

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

双向数据绑定即data = "="不能使用,因为删除函数将在每个$digest循环上运行,这是不好的,因为logging被立即删除并且不会被渲染。

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

当您使用{{title}}时,只有父级作用域值将被传递到指令视图并进行评估。 这仅限于一种方式,这意味着变化将不会反映在父范围内。 当您想要将父指令也作为子指令进行更改时,可以使用'='。 这是两个方面。

我也可以直接访问父范围,而不用装饰我的元素的属性?

当指令具有范围属性(范围:{})时,则不再能够直接访问父范围。 但是仍然可以通过scope。$ parent等来访问它。如果从指令中删除范围,可以直接访问它。

该文件说“通常是希望通过expression式和父范围从隔离的范围传递数据”,但是这似乎也适用于双向绑定。 为什么expression路线会更好?

这取决于上下文。 如果你想用数据调用一个expression式或者函数,你可以使用&和如果你想共享数据,你可以使用biderectional的方式使用'='

您可以在下面的链接中find将数据传递给指令的多种方法之间的区别:

AngularJS – 隔离范围 – @ vs = vs&

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

@=看到其他答案。

一个关于&
TL; DR;
&从父类获取expression式 (不仅在函数中,像其他答案中的例子),并将其设置为指令中的函数,即调用expression式。 而且这个函数有能力用variables传递一个对象来replaceexpression式的任何variables (偶函数名)。

解释
&是一个expression式引用,这意味着如果你传递像<myDirective expr="x==y"></myDirective>
在指令中,这个expr将是一个调用expression式的函数,如:
function expr(){return x == y}
所以在指令的html <button ng-click="expr()"></button>将调用expression式。 在指令的js中, $scope.expr()也会调用expression式。
该expression式将用$ scope.x和$ scope.y来调用。
你有能力重写参数!
如果你通过调用来设置它们,例如<button ng-click="expr({x:5})"></button>
那么这个expression式将会用你的参数x和parant的参数y来调用。
你可以重写这两个。
现在你知道,为什么<button ng-click="functionFromParent({x:5})"></button>起作用。
因为它只是调用父expression式(例如<myDirective functionFromParent="function1(x)"></myDirective> )并用您指定的参数replace可能的值,在本例中为x
它可能是:
<myDirective functionFromParent="function1(x) + 5"></myDirective>
要么
<myDirective functionFromParent="function1(x) + z"></myDirective>
带小孩电话:
<button ng-click="functionFromParent({x:5, z: 4})"></button>
甚至用functionreplace:
<button ng-click="functionFromParent({function1: myfn, x:5, z: 4})"></button>

它只是一个expression式,不pipe它是一个函数,还是许多函数,或者只是比较。 你可以replace这个expression式的任何variables。

例子:
以下作品:
父母定义了$ scope.x,$ scope.y
父模板: <myDirective expr="x==y"></myDirective>
指令模板: <button ng-click="expr()"></button>
指令模板: <button ng-click="expr({x: 5})"></button>
指令模板: <button ng-click="expr({x:5, y:6})"></button>

父母定义了$ scope.function1,$ scope.x,$ scope.y
父模板: <myDirective expr="function1(x) + y"></myDirective>
指令模板: <button ng-click="expr()"></button>
指令模板: <button ng-click="expr({x: 5})"></button>
指令模板: <button ng-click="expr({x:5, y:6})"></button>
指令有$ scope.myFn作为函数
指令模板: <button ng-click="expr({function1: myFn, x:5, y:6})"></button>

@属性string绑定(单向)=双向模型绑定和callback方法绑定