AngularJS:指令隔离作用域 - 作用域变量未定义。

3
请问能有人解释一下,为什么attrDir的作用域变量是可见的,而oneWay的不可见呢?我原本认为scope: {}也是被隔离的。
angular.module('test', []);

angular.module('test').directive('attrDir', attrDir);

function attrDir(){
    return {

        scope: true,

        link: function(scope){
          scope.hello = 'attrDir';
        }

    };
}

angular.module('test').directive('oneWay', oneWay);

function oneWay(){
    return {

        scope: {
          data: '<?'
        },

        link: function(scope){
          scope.hello = 'oneWay';  
        }

    };
}

hello 只会在 attr-dir 中呈现。

<attr-dir>
  <span>{{hello}}</span>
</attr-dir>
<one-way>
  <span>{{hello}}</span>
</one-way>

这里有一个plunker链接: https://plnkr.co/edit/2CM4vVRshWuJvaBj2q8T?p=preview。谢谢。

需要注意的是,没有一个答案正确地回答了这个问题。 - Estus Flask
Estus 是正确的 - one way !== isolated scopes. - lin
@lin,请在此处查看正确答案:https://dev59.com/M5_ha4cB1Zd3GeqP6uYP#42735839 - Max Koretskyi
现在Kindzuko的力量与他同在。 - lin
4个回答

2
首先,你所观察到的与 < 绑定没有任何关系。
问题在于这两个指令中的表达式 {{hello}} 不是这些指令的模板的一部分。对于这样的元素,绑定规则是不同的。
Angular 自动为 {{hello}} 表达式创建链接函数。但是,在你的情况下,对这些链接函数进行评估的作用域是不同的。
你可能期望的是:
            rootScope
         /             \
        /               \
attr-dir-new-scope  one-way-isoloate-scope
      /                   \
     /                     \
{{hello}}               {{hello}}

然而,根据源代码中的此注释

// 如果隔离指令具有模板,则只传递隔离作用域,
// 否则子元素不属于隔离指令。

实际情况是这样的:

             root scope
         /             \    \
        /               \    \
attr-dir-new-scope       \    one-way-isoloate-scope
      /                   \
     /                     \
{{hello}}               {{hello}}

所以在你的例子中,第一个指令<attr-dir>并没有创建隔离作用域,而是创建了新的作用域,因此当链接Angular时,它将这个新的作用域传递给你的指令的链接函数:
link: function(scope){
     scope.hello = 'attrDir';
}

并且针对{{hello}}表达式创建的链接函数。这就是为什么当您在链接函数中添加一个值时,它在表达式链接函数中可用的原因。
但是,您的第二个指令<one-way>创建了隔离作用域,根据我上面提到的评论,该指令的链接函数将得到隔离作用域,但表达式的链接函数将接收不同的作用域(在您的示例中为根作用域)。因此,您正在不同的作用域上添加hello值。这就是值未定义的原因。

1
@GangadharJannu,“>? ”没有实现独立范围,独立范围是通过在指令定义对象中为 scope 属性指定对象来实现的。 - Max Koretskyi
如果是这种情况,<? 代表什么意思? - Buddybear
顺便提一下,那不是 >?,原帖作者在他的指令中尝试了 <? - Buddybear
@GangadharJannu,我现在没有时间。你可以提出一个问题,稍后我会在那里回答。它是<,请参见此处中的正则表达式@&<?只是表示它是可选的。 - Max Koretskyi
@Maximum 我知道 ? 的含义。我们不能假设在 Angular 源代码中有什么,但是我们正在回答 OP 所问的问题。问题中是 data: '<?' - Buddybear
显示剩余3条评论

0

无论是 scope: true 还是 scope:{},都会为指令创建一个子作用域。但是,

scope:true 将从父级(即指令所属的控制器)原型继承属性,而asscope:{}则不会从父级继承属性,因此被称为隔离作用域。

由于oneWay是一个隔离作用域指令,并且您没有传递hello,因此在HTML中未定义。


0

如果未指定作用域,则为共享作用域。 如果将作用域指定为 true,则为继承作用域。 如果使用花括号指定作用域,则为隔离作用域。

最好的方法是在链接函数中使用 console.log 语句来可视化作用域,如下所示:

link: function(scope) {          
      scope.hello = 'attrDir';
      console.log('scope in attrDir: ', scope);
    }

    link: function(scope) {          
          scope.hello = 'oneWay';
          console.log('scope in oneWay: ', scope);
        }

如果你打开开发者工具,你会看到第一个指令在其原型中继承了父级作用域。
__proto__:Scope 

然而第二个是带有独立作用域的对象(通过使用花括号给它一个隔离作用域)

__proto__:Object

-2

因为你正在指令中实现组件绑定。

< 符号表示单向绑定,自 1.5 版本起可用。

如果你想在 one-way 组件中显示 hello,你应该像下面这样更改实现:

HTML

 <one-way hello="$ctrl.hello">
      <span>{{$ctrl.hello}}</span>
    </one-way>

JS

angular.module('test').component('oneWay', {
  bindings:{
    hello:'='
  },
  controller: function() {
    this.hello = 'oneWay';
  }
});

演示

plnkr


那么,您的意思是使用 <directive 在幕后变成了组件? - Kindzoku
@Kindzoku,请在此处查看正确答案:https://dev59.com/M5_ha4cB1Zd3GeqP6uYP#42735839 - Max Koretskyi
@所有人,在给我投票之前,请先说明您的上下文,这样我才能查看。 - Buddybear
@GangadharJannu,“angular 1.5组件绑定”适用于指令模板,而OP案例中没有任何指令使用模板。此外,<符号也适用于指令,因为组件在幕后是一个指令。第三,OP在他的示例中使用了1.5版本。 - Max Koretskyi
@GangadharJannu,请查看这个plunker,以了解在指令中使用<。此外,您可以在这里看到组件只是一个花哨的指令。 - Max Koretskyi
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接