为什么一个DOM元素拥有两个范围?

时间:2016-06-10 05:53:49

标签: angularjs angularjs-directive angularjs-scope

以下是两个指令:

  1. aDirective,创建一个新的孤立范围;

  2. bDirective不会创建新范围。

    app.directive('aDirective', [function () {
        return {
            restrict: 'A',
            scope: {},                         // isolated scope
            link: function (scope, iElement, iAttrs) {
    
            }
        };
    }])
    .directive('bDirective', [function () {
        return {
            restrict: 'A',
            scope: false,
            link: function (scope, iElement, iAttrs) {
    
            }
        };
    }]);
    
  3. 现在将这两个指令应用于一个DOM元素:

    <div ng-app="myApp"> 
       <div ng-controller="myController">
    
            <input id="targetElement" type="text" a-directive  b-directive />
       </div>
    </div>
    

    我得到的结果是它检索目标元素的范围。

    //true
    angular.element("#targetElement").isolateScope().$parent 
    === angular.element("#targetElement").scope()
    

    所以我的问题是为什么单个DOM元素同时拥有两个范围(非隔离范围和隔离范围)。

1 个答案:

答案 0 :(得分:1)

因为在第一个指令中你有一个独立的范围,这意味着它有自己的范围,但是如果检查它的父对象,你仍然会在那里找到父控制器。

让我们说如果我的控制器如下所示

app.controller('myController', function($scope) {
    $scope.obj='abc'
})

我只有一个名为 obj

的属性

案例1:隔离范围 现在,如果我创建像你的指令

app.directive('aDirective', [function () {
    return {
        restrict: 'A',
        scope: {},                         // isolated scope
        controller: function ($scope) {
            console.dir($scope)
        },
        link: function (scope, iElement, iAttrs) {
            console.log('From aDirective')
            console.dir(scope)
        }
    };
}])

此处范围是隔离的,这意味着该指令不会共享父控制器的任何属性。但是如果想拥有在控制器范围内声明的属性,可以访问范围变量的父属性。

在下图中,我试图在隔离范围内显示对象层次结构 enter image description here

在上面的图像中,您可以看到顶层没有obj属性,但您可以在对象的$ parent属性中看到它,实际上是父控制器范围,如下所示

enter image description here

案例2:共享范围

现在在我的范围未被隔离且其实际共享的指令中,如下所示

app.directive('bDirective', [function () {
      return {
          restrict: 'A',
          scope: false,
          controller: function ($scope) {
              console.dir($scope)
          },
          link: function (scope, iElement, iAttrs) {
              console.log('From bDirective')
              console.dir(scope)
          }
      };
  }]);

这里,当我将探索范围对象的对象层次结构时,我将仅在顶部找到obj属性,不需要$ parent属性来获取在父控制器中声明的属性,因为您正在共享范围

enter image description here

现在回到你的问题

//true
angular.element("#targetElement").isolateScope().$parent 
=== angular.element("#targetElement").scope()

上面的代码将始终返回true,因为两者都使用相同的控制器,并且您将隔离范围的$ parent对象与共享范围进行比较,共享范围只是控制器的范围。

如果你comapare

 angular.element("#targetElement").isolateScope()
    === angular.element("#targetElement").scope()

你会得到假的。

同样在最大值时,使用指令时只能有两个范围,即父范围和指令范围。

由于您创建了一个具有隔离范围和其他具有共享范围的范围,因此具有最多两个范围的规则正在实现,这就是它工作的原因。

如果您的指令具有如下所示的范围,则它将无效并且会给您例外(如果两个指令都装饰在一个元素上)

Directive1-> {} and Directive2 -> {}
Directive1-> {} and Directive2 -> true
Directive1-> true and Directive2 -> {}

因此,如果范围如下所示(如果两个指令都在一个元素上修饰),则指令的唯一方法将起作用

Directive1-> {} and Directive2 -> false
Directive1-> false and Directive2 -> {}
Directive1-> false and Directive2 -> false