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

以下是一些相关片段:

来自HTML: <窗格bi-title = "标题" title =“{{标题}}>{{文本}}> < /窗格 从窗格指令: scope: {biTitle: '=', title: '@', bar: '='},

有几件事我不明白:

为什么我必须使用“{{title}}”与“@”和“title”与“=”? 我也可以直接访问父范围,而不装饰我的元素与属性? 文档说:“通常情况下,通过表达式将数据从孤立的作用域传递到父作用域是可取的”,但这似乎也适用于双向绑定。为什么表达式路由会更好呢?

我发现另一个小提琴,显示表达式解决方案太:http://jsfiddle.net/maxisam/QrCXh/


当前回答

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


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


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


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

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

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


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

<child-component 
  foo = "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: '<'
  }
});

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


要查看不同前缀的作用,请打开这个插件。

One-time binding(initialization) using ::

(官方文档) AngularJS的后续版本引入了一次性绑定的选项,其中子作用域属性只更新一次。这样就不需要监视父属性,从而提高了性能。语法与上面不同;要声明一个一次性绑定,在组件标记的表达式前面添加::::::

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

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

总结

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

其他回答

这里有很多很好的答案,但我想就@、=和&绑定之间的差异提供我的观点,这对我来说很有用。

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

@ 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'})

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

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

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

@字符串 =模型 &方法

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

= @ &

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

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

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

子作用域:如果指定该指令的作用域变量为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.
        }
    };
});

隔离作用域:当您想要创建不继承于控制器作用域的作用域时使用。

这发生在你创建插件时,因为这使得指令通用,因为它可以放在任何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-directive
  class="directive"
  name="{{name}}"
  reverse="reverseName()"
  color="color" >
</div>

这里有一个博客的链接,很好地描述了它。

我们可以简单地使用:-

@:-用于单向数据绑定的字符串值。在一种方式中,数据绑定只能将作用域值传递给指令 =:- for对象值用于双向数据绑定。数据绑定有两种方式,你可以在指令和HTML中改变作用域值。 &:-用于方法和函数。

EDIT

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

=双向数据绑定:-如果我们改变了值,它会自动更新 <单向绑定:-当我们只想从父作用域读取参数而不更新它时。 @这是字符串参数 &这是为了回调,以防你的组件需要输出一些东西到它的父作用域

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

@意味着变量将被复制(克隆)到指令中。

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

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

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

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

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

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

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