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

以下是一些相关片段:

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

有几件事我不明白:

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

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


当前回答

我们可以简单地使用:-

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

EDIT

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

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

其他回答

我创建了一个小的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-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>

有三种方法可以在指令中添加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>

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

这个问题已经被折腾得够呛了,但我还是要分享一下,以防其他人也在纠结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会监视它,直到它发生变化,然后对子作用域中相应的属性进行一次性更新。

总结

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

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

@ and =见其他答案。

一个人抓住了你& TL,博士; &从父函数中获取表达式(不仅仅是其他答案中的例子中的函数),并将其设置为指令中的函数,该函数调用表达式。这个函数能够替换表达式的任何变量(甚至函数名),通过将变量传递给一个对象。

explained & is an expression reference, that means if you pass something like <myDirective expr="x==y"></myDirective> in the directive this expr will be a function, that calls the expression, like: function expr(){return x == y}. so in directive's html <button ng-click="expr()"></button> will call the expression. In js of the directive just $scope.expr() will call the expression too. The expression will be called with $scope.x and $scope.y of the parent. You have the ability to override the parameters! If you set them by call, e.g. <button ng-click="expr({x:5})"></button> then the expression will be called with your parameter x and parent's parameter y. You can override both. Now you know, why <button ng-click="functionFromParent({x:5})"></button> works. Because it just calls the expression of parent (e.g. <myDirective functionFromParent="function1(x)"></myDirective>) and replaces possible values with your specified parameters, in this case x. it could be: <myDirective functionFromParent="function1(x) + 5"></myDirective> or <myDirective functionFromParent="function1(x) + z"></myDirective> with child call: <button ng-click="functionFromParent({x:5, z: 4})"></button>. or even with function replacement: <button ng-click="functionFromParent({function1: myfn, x:5, z: 4})"></button>.

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

例子: 指令模板vs调用代码: Parent已经定义了$scope。x, scope.y美元: parent template: <myDirective expr="x==y"></myDirective> <按钮ng-click = " expr ()></button>调用$scope.x==$scope.y <button ng-click="expr({x: 5})"></按钮>调用5 == $scope.y <button ng-click="expr({x:5, y:6})"></button>调用5 == 6

Parent已经定义了$scope。function1,美元范围。x, scope.y美元: : <myDirective expr="function1(x) + y"></myDirective>

<按钮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})">调用$scope.function1(5) + 6 指令有$作用域。myFn作为函数: <button ng-click="expr({function1: myFn, x:5, y:6})"></button>调用$scope.myFn(5) + 6