美文网首页
Controller As与$scope的区别($scope篇)

Controller As与$scope的区别($scope篇)

作者: AkiraPan | 来源:发表于2016-01-21 16:11 被阅读908次

在Angular 1.2以后的版本中,对于嵌套Controller的$scope处理就一直是一个很大的坑,这部分主要得益于JavaScript语言级对继承机制(原型继承)。
本文主要分析Angular对于嵌套Controller作用域的另外一种解决方法,使用controller as 语法进行处理。
上篇为$scope的示例分析,下篇为controller as的示例分析。

$scope的传统写法示例

假设我们在有3个Controller进行嵌套,打印出同一个变量,使用$scope的代码是

controller.js

angular.module('app')
  .controller('MainCtrl', function ($scope) {
    $scope.title = "第一层";
  })
  .controller('AnotherCtrl', function ($scope) {
    $scope.title = "第二层";
  })
  .controller('YetAnotherCtrl', function ($scope) {
    $scope.title = "第三层";
  })

与之对应的view代码则为

view.html

<div ng-controller="MainCtrl">
  {{ title }}
  <div ng-controller="AnotherCtrl">
    {{ title }}
    <div ng-controller="YetAnotherCtrl">
      {{ title }}
    </div>
  </div>
</div>

则HTML的页面结果就是

<div ng-controller="MainCtrl" class="ng-scope ng-binding">
  第一层
  <div ng-controller="AnotherCtrl" class="ng-scope ng-binding">
    第二层
    <div ng-controller="YetAnotherCtrl" class="ng-scope ng-binding">
      第三层
    </div>
  </div>
</div>

$scope的继承机制

继承

如当第三层的YetAnotherCtrl不在自己的$scope内对title变量做赋值操作,则$scope.title会指向上一层的AnotherCtrl中的$scope中进行调用,这里有一个向上寻找的过程,很类似Java中的多态实现(但只是类似)。
故修改controller.js,注释删除掉内部两个ctrl的赋值语句。

controller.js

angular.module('app')
  .controller('MainCtrl', function ($scope) {
    $scope.title = "第一层";
  })
  .controller('AnotherCtrl', function ($scope) {
   // $scope.title = "第二层";
  })
  .controller('YetAnotherCtrl', function ($scope) {
   // $scope.title = "第三层";
  })

则对应的view输出怎么会变为

<div ng-controller="MainCtrl" class="ng-scope ng-binding">
  第一层
  <div ng-controller="AnotherCtrl" class="ng-scope ng-binding">
      第一层
    <div ng-controller="YetAnotherCtrl" class="ng-scope ng-binding">
        第一层
    </div>
  </div>
</div>

YetAnotherCtrl与AnotherCtrl因为在自己的$scope中未对title属性做复制,则会一层一层向父类$scope去调用,最后在MainCtrl中发现了title的并进行调用。

调用父类

回到最初如果3个Ctrl分别对title键值做出了赋值,我们需要显式的在第三层中调用第一层的title值需要怎么做呢?

controller.js

angular.module('app')
  .controller('MainCtrl', function ($scope) {
    $scope.title = "第一层";
  })
  .controller('AnotherCtrl', function ($scope) {
    $scope.title = "第二层";
  })
  .controller('YetAnotherCtrl', function ($scope) {
    $scope.title = "第三层";
  })

view.html

<div ng-controller="MainCtrl">
  {{ title }}
  <div ng-controller="AnotherCtrl">
    {{ title }}
     {{$parent.title}}

    <div ng-controller="YetAnotherCtrl">
      {{ title }}
      {{$parent.title}}
    </div>
  </div>
</div>

我们需要通过$parent去直接操作当前$scope的父$scope去显示其内部的值,根据以上代码则会显示如下的html结果

<div ng-controller="MainCtrl" class="ng-scope ng-binding">
  第一层
  <div ng-controller="AnotherCtrl" class="ng-scope ng-binding">
      第二层  第一层
    <div ng-controller="YetAnotherCtrl" class="ng-scope ng-binding">
        第三层  第二层
    </div>
  </div>
</div>

终极版

最后,如果我们去掉第二层的title赋值语句将controller.js改成

angular.module('app')
  .controller('MainCtrl', function ($scope) {
    $scope.title = "第一层";
  })
  .controller('AnotherCtrl', function ($scope) {
   // $scope.title = "第二层";
  })
  .controller('YetAnotherCtrl', function ($scope) {
    $scope.title = "第三层";
  })

那么刚才最终获得HTML会变成什么样呢?
答案是

<div ng-controller="MainCtrl" class="ng-scope ng-binding">
第一层
<div ng-controller="AnotherCtrl" class="ng-scope ng-binding">
第一层 第一层
<div ng-controller="YetAnotherCtrl" class="ng-scope ng-binding">
第三层 第一层
</div>
</div>
</div>
主要原理如下

  • 当第三层YetAnotherCtrl调用$scope.title的时候,因为YetAnotherCtrl中又对应的操作故最后获取的是自己所赋值的字符串;
  • 当第三层YetAnotherCtrl调用$parent.title。则$parent会先去查找Another中的$scope是否有title值,结果是没有的,故会再向上找,找到MainCtrl中的title值。
  • 当第二层AnotherCtrl调用$scope.title的时候,同理因为本身没有故会向上查找;

小结

$scope相当于给所有的controller提供了可继承共享的上下文,很灵活,副作用是不好排错、子类调用父类的代码变得非常的不好理解,并且原型继承天生有很多坑。
相关的文章可见官方一篇介绍$scope的专题:
https://github.com/angular/angular.js/wiki/Understan:ding-Scopes

相关文章

网友评论

      本文标题:Controller As与$scope的区别($scope篇)

      本文链接:https://www.haomeiwen.com/subject/fsblkttx.html