What is the difference between '@' and '=' in directive scope in AngularJS?
我已经仔细阅读了关于这个主题的AngularJS文档,然后胡乱摆弄了一个指令。这是小提琴。
下面是一些相关的片段:
从HTML:
1<pane bi-title="title" title="{{title}}">{{text}}</pane>从pane指令:
1scope: { biTitle: '=', title: '@', bar: '=' },
有几件事我不明白:
- 为什么我要用
"{{title}}" 和'@' 以及"title" 和'=' 呢? - 我还可以直接访问父作用域,而不需要用属性来修饰我的元素吗?
- 文档中说,"通常希望通过表达式将数据从独立作用域传递到父作用域",但对于双向绑定来说,这似乎也很好。为什么表达路径会更好?
我还找到了另一个显示表达式解决方案的工具:http://jsfiddle.net/maxisam/qrcxhxh/
Why do I have to use"{{title}}" with '@' and"title" with '='?
@将本地/指令作用域属性绑定到dom属性的计算值。如果使用
=将本地/指令作用域属性绑定到父作用域属性。因此,使用=,可以使用父模型/作用域属性名称作为dom属性的值。不能将
使用@,您可以执行诸如
使用@时,如果需要使用链接函数中的值,则需要使用
使用=,您不需要使用$observe。
Can I also access the parent scope directly, without decorating my element with an attribute?
是的,但前提是不使用隔离范围。从指令中删除此行
然后您的指令将不会创建新的作用域。它将使用父作用域。然后可以直接访问所有父作用域属性。
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'})
我发现,通过使用较短的描述来引用范围绑定,更容易记住这些差异:
@ 属性字符串绑定= 双向模型绑定& 回调方法绑定
这些符号还使指令实现中作用域变量所代表的内容更加清晰:
@ 串= 型& 法
为了有用(无论如何对我来说):
据我所知,
如果需要更改父作用域中的多个变量,可以从指令内对父作用域执行函数(或通过服务传递数据)。
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>" }; }); |
- 这不会创建任何绑定。你只是把你传进来的单词当作一个字符串
- 控制器所做的更改将反映在指令持有的参考中,反之亦然。
- 调用此getter函数后,结果对象的行为如下:
- 如果传递了一个函数:那么当调用时,该函数将在父(控制器)闭包中执行。
- 如果传入了非函数:只需获取没有绑定的对象的本地副本
这把小提琴应该演示它们是如何工作的。特别注意名称中带有
指令中有三种添加范围的方法:
指令和它的父(控制器/指令)作用域相同。因此,对指令内的作用域变量所做的任何更改也会反映在父控制器中。您不需要指定它,因为它是默认的。
在这里,如果您更改指令内的作用域变量,它不会反映在父作用域中,但是如果您更改作用域变量的属性,即反映在父作用域中,正如您实际修改了父作用域变量一样。
例子,
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指令作用域"@"和"="
即使范围是本地的,例如在您的示例中,您也可以通过属性
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: '@', } |
这里,子作用域中的
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' } }); |
给定
1 | 15xyz |
您希望何时使用这种复杂的功能?
使用
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)传播到子作用域,而不建立单向或双向绑定。注:如果
下表显示了前缀的工作方式,具体取决于属性是否为对象、数组、字符串等。
这是
知道了一个关于
explained 在这一
它是表达的不安,有物或如果它是一个多功能的,或是函数的比较。你可以和任何变量本replace函数表达。 </P >
例子: 指令模板和应用代码: 父母有定义的scope.x美元,美元的scope.y: 父母
父母有定义的scope.function1 scope.x美元,美元,美元的scope.y: 父母
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 >