4

controllerAs做了什么

我们在定义路由时

.state('account.register', {
    url: '/register',
    templateUrl: 'app/account/register.html',
    controller: 'RegisterCtrl',
    controllrtAs: 'vm'
})

在angular的源代码中:

locals.$scope[state.controllerAs] = controllerInstance;

可以发现angular把控制器的实例作为$scope上以controllerAs的值为名称的对象属性上了。
我们用Batarang查看一下
图片描述

发现确实是这样。

为什么要使用controllerAs

  1. $scope是基于原型进行继承的,比如说当我们查找一个user对象时,angular会先查找当前$scope有没有user,如果没有的话就继续往上层$scope查找,直至$rootScope。
    图片描述
    而在controllerAs中,假设我们使用controllerAs

    UserCtrl as ctrl
    angular将控制器自身挂载在$scope上,user也变为ctrl.user,就不会存在上述的一层层查找的过程。在很多情况下,比如在嵌套的路由中,上述$scope基于原型的查找,有时候确实会提供一些便利,但这些都可以用服务来实现,也应该使用服务来实现。
    图片描述

  2. 大家在初次接触angular时一定会被推荐过将所有数据都绑定在$scope的一个对象上(比如$scope.data)来避免一些js中值的复制和对象的引用可能会造成的一些问题(公司里的新人大部分也确实遇到过这类问题),而使用controllerAs后就不需要这一步了,因为人家本来就是。

  3. 因为不使用$scope也就不能使用$on,$watch,$emit之类的方法,这些方法本来就应该尽量少用,这样就可以更好的控制项目中的代码,当不得不用这类方法时可以参考下面的案例。

  4. 便于新人学习,我发现新人对于$scope这个东西往往无法理解,而用controllerAs vm之后,则将vm(view model的简写)作为视图模型则比较好理解。

当必须要使用$watch($on、$emit、$broadcast)时该怎么做

当出现这种情况时我们可以把$scope当做单纯的一种服务来使用,他提供了上述的方法,比如:

function MyCtrl ($scope) {
    var vm = this;
    vm.name = 'liulei';
    vm.count = 0;
    $scope.$watch('vm.count', function (newVal, oldVal) {
        vm.count ++;
    });
}

在指令中使用controllerAs

在指令中如果不需要数据绑定时,我们简单的将scope这个选项设置为true或者{}即可,可当我们需要从外部绑定一个值或者对象到指令中该怎么办呢?因为我们知道如果用scope选项的话,肯定是绑定到指令的scope对象上的,这里我们直接使用bindToController选项即可,上代码

'use strict';
angular.module('nodeInAction')
.directive('countCard', function () {
    return {
        restrict: 'E',
        controllerAs: 'vm',
        scope: {},
        bindToController: {
            icon: '@',
            title: '@',
            count: '@',
            unit: '@',
            colorStyle: '@'
        },
        templateUrl: 'app/components/countCard/countCard.html',
        controller: function () {
            var vm = this;        
            console.log(vm);
        }
    };
});

图片描述
结果也是我们想要的结果。bindToController的作用的作用也很好理解也就是将属性绑定到controller自身上。
也可以这样写

'use strict';
angular.module('nodeInAction')
.directive('countCard', function () {
    return {
        restrict: 'E',
        scope: {
            icon: '@',
            title: '@',
            count: '@',
            unit: '@',
            colorStyle: '@'
        },
        controllerAs: 'vm',
        bindToController: true,
        templateUrl: 'app/components/countCard/countCard.html',
        controller: function () {
            var vm = this;        
            console.log(vm);
        }
    };
});

效果是一样的。


Jax2000
1.9k 声望295 粉丝

前端开发,热爱钻研,擅长Angular(ionic)1 2,Node,rxjs