'@'和& # 39;= & # 39;在AngularJS的指令范围?

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

以下是一些相关片段:

  • 超文本标记语言:

    <pane bi-title="title" title="{{title}}">{{text}}</pane>
  • From the pane directive:

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

There are several things I don't get:

  • Why do I have to use "{{title}}" with '@' and "title" with '='?
  • 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 expression and to the parent scope", but that seems to work fine with bidirectional binding too. Why would the expression route be better?

I found another fiddle that shows the expression solution too: http://jsfiddle.net/maxisam/QrCXh/

565693 次浏览

=表示双向绑定,即父作用域的变量引用。这意味着,当你在指令中改变变量时,它也会在父作用域中被改变。

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

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

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

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

@将局部/指令作用域属性绑定到DOM属性的评估值。如果使用title=title1title="title1",DOM属性“title”的值就是字符串title1。如果你使用title="\{\{title}}",DOM属性“title”的值是插入的\{\{title}}的值,因此字符串将是父范围属性“title”当前设置的值。因为属性值总是字符串,所以当使用@时,在指令的作用域中,这个属性的值总是以字符串结束。

将局部/指令作用域属性绑定到父范围属性。因此,对于,您使用父模型/作用域属性名作为DOM属性的值。你不能用\{\{}}

使用@,你可以做类似title="\{\{title}} and then some"——\{\{title}}插入的事情,然后字符串“and them some”与它连接。最后一个串接的字符串是local/directive scope属性得到的。(你不能用第一条,只能用第二条。)

对于@,如果您需要在link(ing)函数中使用该值,则需要使用attr.$observe('title', function(value) { ... })。例如,第一条不会像你期望的那样工作。注意,这意味着您只能访问属性异步< em > < / em >。如果只使用模板中的值,则不需要使用$observe()。例如,# 0。< / p >

对于,您不需要使用$observe。

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

是的,但前提是你不使用孤立的作用域。从指令中删除这一行

# 0

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

文档中说:“通常情况下,通过表达式将数据从孤立的作用域传递到父作用域是可取的”,但这似乎也适用于双向绑定。为什么表达式路由会更好呢?

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

另请参阅

即使作用域是本地的,就像在您的例子中,您也可以通过属性$parent访问父作用域。假设在下面的代码中,title是在父作用域上定义的。然后你可以访问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>

渲染的一部分是删除按钮,在这里通过&从外部作用域附加一个删除函数是有用的。在渲染指令中,它是这样的

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

2-way数据绑定,即data = "="不能使用,因为删除函数将在每个$digest循环中运行,这是不好的,因为记录将立即被删除,并且永远不会呈现。

如果您想通过一个现场示例了解更多这是如何工作的。# 0

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

这里有很多很好的答案,但我想谈谈我对@=&绑定之间的区别的看法,这些区别对我来说很有用。

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

  1. @绑定用于传递字符串。这些字符串支持插入值的\{\{}}表达式。例如:. 对插值表达式求值指令的父作用域。

  2. 绑定用于双向模型绑定。父作用域中的模型链接到指令孤立作用域中的模型。更改一个模型影响另一个模型,反之亦然。

  3. ,绑定用于将方法传递到指令的作用域,以便它可以在指令中调用。该方法被预先绑定到该指令的父作用域,并支持参数。例如,如果方法在父作用域中是hello(name),则在为了从指令内部执行该方法,必须调用scope.hello美元({名称:‘世界’})< / p > < /李>

我发现通过一个更短的描述来参考作用域绑定更容易记住这些区别:

  • # 0 # 1
  • # 0 # 1
  • # 0 # 1

这些符号还可以更清楚地说明作用域变量在指令实现中的含义:

  • # 0 # 1
  • # 0 # 1
  • # 0 # 1

按用处排序(至少对我来说):

  1. @
  2. ,

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

  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 scopescope.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  )

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

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

是双向的,所以如果你改变指令作用域中的变量,控制器作用域中的变量也会受到影响

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

这里的优点是变量的名称在控制器作用域和指令作用域中不需要相同。

例如,指令作用域有一个变量“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-directiveclass="directive"name="\{\{name}}"reverse="reverseName()"color="color" ></div>

这里有一个链接的博客描述得很好。

# 0 # 1

  • 这不会创建任何绑定。您只是获得作为字符串传入的单词

# 0 # 1

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

它的行为有点不同,因为作用域获得了返回传入的对象的函数。我想这是成功的必要条件。#2

  • 调用此getter函数后,结果对象的行为如下:
    • 如果传递了函数:则函数在父(控制器)闭包中被调用时执行
    • 如果传入了功能:简单地获取没有绑定的对象的本地副本
    • 李< / ul > < / >
    < p > < br ># 2。特别注意名称中带有get...的作用域函数,希望能更好地理解我所说的&

我创建了一个小的HTML文件,里面有Angular代码来演示它们之间的区别:

<!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-dirattr1="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>

我一次性实现了所有可能的选项。

它处理所有的选项:

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

https://jsfiddle.net/rishulmatta/v7xf2ujm

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

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

,局部作用域属性允许指令的使用者传入该指令可以调用的函数。

请查看下面的链接,它会用例子让你清楚地理解。我发现它真的很有用,所以想分享它。

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

的方式是双向绑定的,它让你在指令中有生活的变化。当有人在指令外更改变量时,你将在指令内拥有更改的数据,但@方式不是川绑定方式。它像文本那样工作。你绑定一次,你就只有它的值。

为了更清楚地理解它,你可以使用这篇很棒的文章:

AngularJS指令作用域'@' and '='

我们可以简单地使用:-

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

  2. =:-为双向数据绑定的对象值。数据绑定有两种方式,你可以在指令和HTML中改变作用域值。

  3. &:-用于方法和函数。

编辑

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

  1. = 双向数据绑定:-如果我们改变值,它会自动更新
  2. < one way binding:-当我们只想从父作用域读取一个参数而不更新它时。

  3. @这是为字符串参数

  4. &这是为回调,以防你的组件需要输出一些东西到它的父作用域

@=看到了其他答案。

一个问题关于# 0
# 0 < br >&从父函数中获取表达式(不仅仅是其他答案中的例子中的函数),并将其设置为指令中的函数,该函数调用表达式。这个函数有能力替换任何变量(甚至函数名)的表达式,通过传递一个对象的变量。< / p > < p > # 0 < br >&是一个表达式引用,这意味着如果你传递类似# 0 < br >在指令中,expr将是一个函数,调用表达式,如:
# 0。< br >在指令的HTML <button ng-click="expr()"></button>中会调用这个表达式。在js的指令中,只有$scope.expr()也会调用表达式该表达式将使用$scope调用。X和$scope。Y的父元素
你有能力重写参数!< br >如果您通过调用设置它们,例如<button ng-click="expr({x:5})"></button>
然后,表达式将使用你的参数x和父参数y来调用
现在你知道为什么<button ng-click="functionFromParent({x:5})"></button>有效了因为它只是调用parent的表达式(例如<myDirective functionFromParent="function1(x)"></myDirective>)并用您指定的参数替换可能的值,在本例中是x.
它可以是:
# 0 < br >或< br ># 0 < br >与子调用:
# 0。< br >甚至用函数替换:
# 0。< / p >

它只是一个表达式,不管它是一个函数,还是多个函数,或者只是比较。你可以替换这个表达式的0号变量。

< p > # 0 < br ># 0 < br ># 0 < br >父模板:<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

< p > # 0 < br >父模板:<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
# 0 < br ><button ng-click="expr({function1: myFn, x:5, y:6})"></button>调用$scope.myFn(5) + 6

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

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

我也可以直接访问父范围,不装饰我的元素的属性?< / p >

当指令中有scope属性(scope:{})时,你将不能再直接访问父作用域。但是仍然可以通过作用域访问它。美元的父母等等。如果从指令中删除作用域,则可以直接访问它。

文档说:“通常需要从隔离作用域通过表达式和父作用域”,但是似乎工作与双向绑定也很好。为什么表达路线更好吗?< / p >

这取决于上下文。如果要调用带有数据的表达式或函数,可以使用&如果你想要共享数据,你可以使用双向方式使用'='

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

AngularJS -隔离作用域- @ vs = vs &

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

属性字符串绑定(单向)=双向模型绑定,回调方法绑定

他们之间的主要区别是

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

@将局部/指令作用域属性绑定到DOM属性的评估值。=将局部/指令作用域属性绑定到父作用域属性。,绑定是为了将一个方法传递到你的指令的作用域,这样它就可以在你的指令中被调用

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

这个问题已经被折腾得够呛了,但我还是要分享一下,以防其他人也在纠结AngularJS作用域这个可怕的烂摊子。这将涵盖=<@&::。完整的报告可以在在这里中找到。


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


<建立了单向绑定,父到子。更改父属性将导致子属性的更改,但更改子属性不会影响父属性。


@将把tag属性的字符串值赋给子属性。如果属性包含表达式,则每当表达式计算为不同的字符串时,子属性就会更新。例如:

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

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


&有点棘手,事实上似乎没有令人信服的理由去使用它。它允许您在父范围内计算表达式,用子范围内的变量替换参数。一个例子(砰砰作响):

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

给定parentVar=10,表达式parentFoo({myVar:5, myOtherVar:'xyz'})将计算为5 + 10 + 'xyz',组件将呈现为:

<div>15xyz</div>

你什么时候想使用这个复杂的功能?&通常被人们用来将父作用域中的回调函数传递给子作用域。然而,在现实中,使用'<'来传递函数可以达到同样的效果,这更直接,并且避免了传递参数时使用笨拙的花括号语法({myVar:5, myOtherVar:'xyz'})。考虑:

使用&的回调:

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

使用<的回调:

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

这意味着即使它是单向绑定,您也在父作用域和子作用域中使用相同的对象。


要查看不同前缀的作用,请打开砰砰作响

使用::的一次性绑定(初始化) < p > # 0 < br >AngularJS的后续版本引入了一次性绑定的选项,其中子作用域属性只更新一次。这样就不需要监视父属性,从而提高了性能。语法与上面不同;要声明一次性绑定,您可以在组件标签中的表达式前面添加:::

<child-componenttagline = "::$ctrl.tagline"></child-component>

这将把tagline的值传播到子作用域,而不需要建立单向或双向绑定。请注意:如果tagline在父作用域中最初是undefined,angular会监视它,直到它发生变化,然后对子作用域中相应的属性进行一次性更新。

总结

下表显示了前缀是如何工作的,这取决于属性是对象、数组、字符串等。

各种隔离作用域绑定如何工作