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

以下是一些相关片段:

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

有几件事我不明白:

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

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


当前回答

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

其他回答

即使作用域是本地的,就像在您的例子中,您也可以通过属性$parent访问父作用域。假设在下面的代码中,标题是在父作用域上定义的。然后你可以通过$parent.title访问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 =" ="不能被使用,因为delete函数会在每个$digest周期上运行,这是不好的,因为记录会立即被删除,并且永远不会呈现。

如果您想通过一个现场示例了解更多这是如何工作的。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>"
    };
});

=方法是双向绑定,它允许你在指令中进行实时更改。当有人在指令外更改变量时,你将在指令内拥有更改的数据,但@ way不是双向绑定。它像文本一样工作。你绑定一次,你就只有它的值。

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

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

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

总结

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

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