Angularjs 属性绑定优先级

Angularjs attribute binding priority

我们实施了下一个指令:

angular.module('app', [])
  .directive('dIsolatedWorks', function() {
    return {
      scope: {
        prop: '='
      },
      template: '<span>{{name}}: {{prop}}</span>',
      link: function(scope) {
        scope.name = 'isolated';
        scope.prop = 'link';
      }
    };
  })
  .directive('dIsolated', function() {
    return {
      scope: {
        prop: '@'
      },
      template: '<span>{{name}}: {{prop}}</span>',
      controller: function($scope) {
        $scope.prop = 'controller';
      },
      link: function(scope) {
        scope.name = 'isolated';
        scope.prop = 'link';
      }
    };
  });
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
  <div d-isolated-works prop="attribute"></div>
  <div d-isolated prop="attribute"></div>
</div>

实际上,在实施过程中,我确信分配给 scope.prop 字段会更改变量,它将显示为 'link',而不是 'attribute'。 但目前我们看到实际值将是 isolated: attribute。 然而,它可以通过将字符串赋值更改为对象赋值来简单地修复。

你能解释一下这种行为吗?

我相信隔离范围内的参数在 linking 阶段之后绑定。这就是为什么您最终得到通过 'prop' 属性传递的值,而不是您在 link 函数中设置的值。

在文档中找不到我所说的 (https://docs.angularjs.org/guide/compiler),但做了一个小实验证明了这一点。

检查 fiddle - 我刚刚在父范围内启动 'attribute' 属性 并且 'dIsolatedWorks' 的工作方式类似于 'dIsolated'

<div ng-app="app">
    {{attribute = 'hello world';}}

    <div d-isolated-works prop="attribute"></div>
    <div d-isolated prop="attribute"></div>
</div>

http://jsfiddle.net/ndfqruxf/

指令 'dIsolatedWorks' 之所以按您预期的那样工作,是因为在其上配置了双向绑定 ('='),但在名为 'attribute' 的父作用域上没有变量。因此,'dIsolatedWorks'指令启动变量。

使用前缀 = 和 @

进行细微更改会产生相同的结果

angular.module('app', [])
.directive('dIsolatedWorks', function () {
return {
    scope: {
        prop: '='
    },
    template: '<span>{{name}}: {{prop}}</span>',
    link: function (scope) {
        scope.name = 'isolated';
        scope.prop = 'link';
    }
};
})
.directive('dIsolated', function ($timeout) {
return {
    scope: {
        prop: '@'
    },
    template: '<span>{{name}}: {{prop}}</span>',
    controller: function ($scope) {
        $scope.prop = 'controller';
    },
    link: function (scope, element, attr) {
        scope.name = 'isolated';
        $timeout(function(){  });
        $timeout(function(){
            console.log('Still I found attrib value: ',scope.prop);
          
          scope.prop = 'link'; // this will change it
            });
        //scope.prop = 'link';
     
    }
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
    <div d-isolated-works prop="attribute"></div>
    <div d-isolated prop="attribute"></div>
</div>

但概念上

@ 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.

牢记以上概念,分析:

1 - 当我们使用前缀 '@' 定义范围时,模板总是从 attrib 获取值(因此 link scope.prop 没有任何影响)

2 - 然后创建 scope 并为其分配属性字符串值

但是

3 - 当第二个摘要周期 运行 (在 ng-clickng-model$timeout 上)它会改变值

4 - 请参阅上面代码中的 $timeout 以了解 (运行 It!)

快乐帮助!

因此,在调查 angularjs 答案代码后,我找到了正确的答案 - 根据 angular.js v1.3.20 我们在 @ 属性的链接函数中有下一行代码(行7698):

      case '@':
            attrs.$observe(attrName, function(value) {
              isolateBindingContext[scopeName] = value;
            });
            attrs.$$observers[attrName].$$scope = scope;
            if (attrs[attrName]) {
              // If the attribute has been provided then we trigger an interpolation to ensure
              // the value is there for use in the link fn
              isolateBindingContext[scopeName] = $interpolate(attrs[attrName])(scope);
            }
            break;

根据这个代码

  1. Angularjs 为属性注册 $observer(evalAsync 因此它将在代码链结束后执行)
  2. 值从属性正确传播,因此我们将在链接函数中看到它的值
  3. 链接函数随属性值传播。
  4. 链接函数更改属性值并完成其工作
  5. 执行回到 $observer 函数(因为它应该至少执行一次)
  6. $observer 被执行并将值更改回属性值

因此我们可以说在指令主体中使用字符串绑定参数只允许作为只读值,直到它被包装到超时块(或任何其他延迟执行)