首页 文章

AngularJS中指令范围内的'@'和'='之间有什么区别?

提问于
浏览
1011

我've read the AngularJS documentation on the topic carefully, and then fiddled around with a directive. Here'是fiddle .

以下是一些相关的片段:

  • 来自HTML:
<pane bi-title="title" title="{{title}}">{{text}}</pane>
  • 从窗格指令:
scope: { biTitle: '=', title: '@', bar: '=' },

我有几件事没有得到:

  • 为什么我必须将 "{{title}}"'@'"title"'=' 一起使用?

  • 我是否也可以直接访问父作用域,而无需使用属性装饰我的元素?

  • 文档说"Often it's desirable to pass data from the isolated scope via an expression and to the parent scope",但这似乎也适用于双向绑定 . 为什么表达路线会更好?

我找到了另一个显示表达式解决方案的小提琴:http://jsfiddle.net/maxisam/QrCXh/

17 回答

  • 1

    @将local / directive范围属性绑定到DOM属性的计算值 . =将本地/指令范围属性绑定到父范围属性 . &binding用于将方法传递到指令的作用域中,以便可以在指令中调用它 .

    @ Attribute string binding =双向模型绑定和Callback方法绑定

  • 0

    他们之间的主要区别就是

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

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

    渲染的一部分是删除按钮,这里通过&附加来自外部范围的删除功能很有用 . 在render-directive里面看起来像

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

    双向数据绑定,即 data = "=" 不能使用,因为删除函数将在每个 $digest 周期运行,这是不好的,因为记录然后立即被删除并且从不呈现 .

  • 3

    @= 见其他答案 .

    一个 gotcha 关于 &
    TL;DR;
    & 从父级获取 expression (不仅像其他答案中的示例中的函数一样),并将其设置为指令中的函数,该函数调用表达式 . 并且通过传递带有变量的对象,此函数能够 replace any variable (甚至函数名称)表达式 .

    explained
    & 是一个表达式引用,这意味着如果你传递类似 <myDirective expr="x==y"></myDirective> 的内容
    在指令中, expr 将是一个函数,它调用表达式,如:
    function expr(){return x == y} .
    所以在指令的html中 <button ng-click="expr()"></button> 会调用表达式 . 在指令的js中, $scope.expr() 也会调用表达式 .
    将使用父级的$ scope.x和$ scope.y调用表达式 .
    您可以覆盖参数!
    如果您通过电话设置,例如 <button ng-click="expr({x:5})"></button>
    然后使用参数 x 和parent的参数 y 调用表达式 .
    你可以覆盖两者 .
    现在你知道了,为什么 <button ng-click="functionFromParent({x:5})"></button> 有效 .
    因为它只调用父表达式(例如 <myDirective functionFromParent="function1(x)"></myDirective> )并用指定的参数替换可能的值,在本例中为 x .
    它可能是:
    <myDirective functionFromParent="function1(x) + 5"></myDirective>
    要么
    <myDirective functionFromParent="function1(x) + z"></myDirective>
    带着孩子的电话:
    <button ng-click="functionFromParent({x:5, z: 4})"></button> .
    甚至功能替换:
    <button ng-click="functionFromParent({function1: myfn, x:5, z: 4})"></button> .

    它只是一个表达式,如果它是一个函数,或许多函数,或只是比较,无关紧要 . 并且您可以替换此表达式的 any 变量 .

    Examples:
    directive template vs called code:
    parent定义了$ scope.x,$ scope.y:
    父模板: <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

    parent定义了$ scope.function1,$ scope.x,$ scope.y:
    父模板: <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
    指令将$ scope.myFn作为函数:
    <button ng-click="expr({function1: myFn, x:5, y:6})"></button> 来电 $scope.myFn(5) + 6

  • 2

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

    @ 将本地/指令范围属性绑定到 evaluated value of the DOM attribute . 如果使用 title=title1title="title1" ,则DOM属性"title"的值只是字符串 title1 . 如果使用 title="{{title}}" ,则DOM属性"title"的值是 {{title}} 的插值,因此该字符串将是当前设置的父范围属性"title" . 由于属性值始终是字符串,因此在使用 @ 时,您将始终在指令范围内以此属性的字符串值结束 .

    = 将本地/指令范围属性绑定到 a parent scope property . 因此,使用 = ,您可以使用父模型/范围属性名称作为DOM属性的值 . 您不能将 {{}}= 一起使用 .

    使用@,您可以执行 title="{{title}} and then some" - {}插补,然后将字符串"and them some"与其连接 . 最终的连接字符串是本地/指令范围属性获取的内容 . (你不能用 = ,只能 @ . )

    使用 @ ,如果需要使用link(ing)函数中的值,则需要使用 attr.$observe('title', function(value) { ... }) . 例如, if(scope.title == "...") 将无法像您期望的那样工作 . 请注意,这意味着您只能访问此属性asynchronously . 如果仅使用模板中的值,则不需要使用$ observe() . 例如, template: '<div>{{title}}</div>' .

    使用 = ,您不需要使用$ observe .

    我还可以访问父范围直接,没有用属性装饰我的元素?

    是的,但仅限于您不使用隔离范围 . 从指令中删除此行

    scope: { ... }

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

    文档说“通常需要通过表达式将数据从隔离范围传递到父范围”,但这似乎也适用于双向绑定 . 为什么表达路线会更好?

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

    也可以看看

  • 38

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

    使用{}时,只有父作用域值将传递给指令视图并进行评估 . 这仅限于一种方式,这意味着更改不会反映在父范围中 . 当您想要将子指令中完成的更改反映到父作用域时,可以使用'=' . 这是双向的 .

    我是否也可以直接访问父作用域,而无需使用属性装饰我的元素?

    当指令中包含scope属性(作用域:{})时,您将无法再直接访问父作用域 . 但仍然可以通过范围访问它 . $ parent等 . 如果从指令中删除范围,可以直接访问它 .

    文档说“通常需要通过表达式将数据从隔离范围传递到父范围”,但这似乎也适用于双向绑定 . 为什么表达路线会更好?

    这取决于具体情况 . 如果要使用数据调用表达式或函数,可以使用&,如果需要共享数据,可以使用'='的二进制方式

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

    AngularJS – Isolated Scopes – @ vs = vs &

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

  • 32

    这里有很多很棒的答案,但我想提供一些关于 @=& 绑定之间差异的观点,这对我来说非常有用 .

    所有三种绑定都是通过元素的属性将数据从父作用域传递到指令的独立作用域的方法:

    @ binding用于传递字符串 . 这些字符串支持插值的{{}}表达式 . 例如: . 插值表达式根据指令的父作用域进行评估 . = binding用于双向模型绑定 . 父范围中的模型链接到指令的隔离范围中的模型 . 对一个模型的更改会影响另一个模型,反之亦然 . &binding用于将方法传递到指令的作用域中,以便可以在指令中调用它 . 该方法预先绑定到指令的父作用域,并支持参数 . 例如,如果方法在父作用域中是hello(name),那么为了从指令内部执行方法,必须调用$ scope.hello({name:'world'})

    我发现通过较短的描述引用范围绑定更容易记住这些差异:

    • @ 属性字符串绑定

    • = 双向模型绑定

    • & 回调方法绑定

    这些符号还使得范围变量在指令实现中的含义更加清晰:

    • @ 字符串

    • = 型号

    • & 方法

    为了有用(对我来说反正):

    • =

    • @

  • 11

    我创建了一个包含Angular代码的HTML文件,演示了它们之间的区别:

    <!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>
    
  • 1

    = 表示双向绑定,因此对父作用域的变量的引用 . 这意味着,当您更改指令中的变量时,它也将在父作用域中更改 .

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

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

    如果需要更改父作用域中的多个变量,可以在指令中对父作用域执行一个函数(或通过服务传递数据) .

  • 35

    = 方式是 2-way binding ,它允许您在指令中进行 live 更改 . 当某人将该变量更改为指令时,您将拥有该指令更改了指令中的数据,但 @ 方式不是 two-ways binding . 它像 Text 一样工作 . 你绑定一次,你将只有它的 Value .

    为了更清楚地了解它,您可以使用这篇伟大的文章:

    AngularJS Directive Scope '@' and '='

  • 3

    我在小提琴中实现了所有可能的选项 .

    它涉及所有选项:

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

    https://jsfiddle.net/rishulmatta/v7xf2ujm

  • 0

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

    = 如果需要在外部作用域和指令的隔离作用域之间创建双向绑定,则可以使用=字符 .

    & local scope属性允许指令的使用者传入指令可以调用的函数 .

    请查看下面的链接,通过示例让您清楚地了解 . 我发现这非常有用,所以想分享它 .

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

  • 20

    @ get as string

    • 这不会创建任何绑定 . 你只是把你传入的单词作为一个字符串

    = 2 way binding

    从控制器进行的

    • 更改将反映在指令持有的引用中,反之亦然

    & 这种行为有点不同,因为范围得到 returns the object that was passed in 的函数 . 我认为这是必要的,以使其工作 . 小提琴应该清楚这一点 .

    • After calling this getter function, the resulting object behaves as follows:

    • 如果传递了一个函数:那么在调用时该函数在父(控制器)闭包中执行

    • 如果传入了非函数:只需获取没有绑定的对象的本地副本

    This fiddle should demonstrate how they work . 在名称中特别注意范围函数 get... ,希望能更好地理解我的意思 &

  • 0

    我们可以使用: -

    • @ : - 用于单向数据绑定的字符串值 . 在某种程度上,数据绑定只能将范围值传递给指令

    • = : - 用于双向数据绑定的对象值 . 在双向数据绑定中,您可以更改指令中的范围值以及html中的范围值 .

    • & : - 用于方法和功能 .

    编辑

    Angular version 1.5 以及 Angular version 1.5 的定义中
    有四种不同类型的绑定:

    • = Two-way data binding : - 如果我们更改了值,它会自动更新

    • < one way binding : - 当我们只想从父作用域读取参数而不更新它时 .

    • @ 这是 String Parameters

    • & 这适用于 Callbacks ,以防您的组件需要输出内容到其父作用域

  • 526

    @ Attribute string binding(单向)=双向模型绑定和Callback方法绑定

  • 61

    指令中可以添加三种范围:

    • Parent scope :这是默认的范围继承 .

    该指令及其父(其所在的控制器/指令)范围是相同的 . 因此,对指令中的范围变量所做的任何更改也会反映在父控制器中 . 您不需要指定它,因为它是默认值 .

    • Child 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.
            }
        };
    });
    
    • Isolated scope :当您要创建不从控制器范围继承的范围时,将使用此选项 .

    当您创建插件时会发生这种情况,因为这会使指令变为通用,因为它可以放在任何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  )
    

    @ 表示来自控制器范围的更改将反映在指令范围中,但如果修改指令范围中的值,则控制器范围变量不会受到影响 .

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

    = 是双向的,因此如果更改指令范围中的变量,控制器范围变量也会受到影响

    & 用于绑定控制器范围方法,以便在需要时可以从指令中调用它

    这里的优点是变量的名称在控制器范围和指令范围内不必相同 .

    例如,指令范围有一个变量“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>
    

    这是博客的link,很好地描述了它 .

  • 6

    如果您想通过实例了解更多这方面的工作原理 . 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>"
        };
    });
    

相关问题