美文网首页
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