专栏名称: 前端JavaScript
分享 | 学习 | 交流 | 原创 分享是学习的开始;学习不必要从头开始,是从现在开始;交流能沟通你我,提高你的学识;期待你的加入!!! web前端技术交流,JavaScript,HTML5,CSS3……
目录
相关文章推荐
51好读  ›  专栏  ›  前端JavaScript

Angular开发者指南(四)控制器

前端JavaScript  · 公众号  · Javascript  · 2017-03-11 07:38

正文


了解控制器controller

在AngularJS中,Controller由JavaScript构造函数定义,用于扩充AngularJS Scope。

当控制器通过ng-controller指令连接到DOM时,AngularJS将使用指定的Controller的构造函数实例化一个新的Controller对象。 将创建一个新的子作用域,并将其作为可注入参数提供给Controller的构造函数作为$ scope。

如果控制器已使用控制器作为语法附加,则控制器实例将被分配给新作用域上的属性。

使用控制器:


  • 设置$scope对象的初始状态。

  • 将行为添加到$scope对象。

不要使用控制器:


  • 操作DOM - 控制器应该只包含业务逻辑。 将任何表示逻辑放入控制器显着影响其可测性。 AngularJS有数据绑定大多数情况下和指令封装手动DOM操作。

  • 格式输入 - 使用AngularJS表单控件。

  • 过滤器输出 - 使用AngularJS过滤器。

  • 在控制器上共享代码或状态 - 使用AngularJS服务。

  • 管理其他组件的生命周期(例如,创建服务实例)。


设置$scope对象的初始状态

通常,当创建应用程序时,需要为AngularJS $ scope设置初始状态。 通过将属性附加到$scope对象来设置作用域的初始状态。 属性包含视图模型(将由视图呈现的模型)。 所有$scope属性将在控制器注册的DOM中的点处可用于模板。

以下示例演示了如何创建一个GreetingController,它附加一个包含字符串'Hola!'的greeting属性在$scope中:


var myApp = angular.module('myApp',[]);

myApp.controller('GreetingController', ['$scope', function($scope) {

  $scope.greeting = 'Hola!';

}]);

我们为我们的应用程序创建一个AngularJS模块myApp。 然后我们使用.controller()方法将控制器的构造函数添加到模块中。 这将使控制器的构造函数保持在全局范围之外。

我们使用了一个内联注入注释来显式地指定Controller对AngularJS提供的$scope服务的依赖。

我们使用ng-controller指令将控制器附加到DOM。 greeting属性现在可以与数据绑定到模板:


  {{ greeting }}


将行为添加到scope对象

为了对事件作出反应或在视图中执行计算,我们必须向scope提供行为。 我们通过将方法附加到$scope对象来将行为添加到作用域。 然后可以从模板/视图调用这些方法。

以下示例使用Controller将一个数字加倍的方法添加到作用域:


var myApp = angular.module('myApp',[]);

myApp.controller('DoubleController', ['$scope', function($scope) {

  $scope.double = function(value) { return value * 2; };

}]);

将控制器附加到DOM后,可以在模板中的AngularJS表达式中调用double方法:


  Two times equals {{ double(num) }}

分配给scope的任何对象(或基元)都将成为模型属性。 分配给作用域的任何方法都在模板/视图中可用,并且可以通过AngularJS表达式和ng事件处理程序指令(例如ngClick)调用。

正确使用控制器

一般来说,控制器不应该尝试做太多。 它应该只包含单个视图所需的业务逻辑。

保持Controllers精简的最常见的方法是将不属于控制器的工作封装到服务中,然后通过依赖注入在Controllers中使用这些服务。

将控制器与AngularJS Scope对象相关联

可以通过ngController指令或$route服务隐式地将控制器与scopes对象相关联。

简单的控制器(spicy)示例

为了进一步说明Controller组件如何在AngularJS中工作,让我们使用以下组件创建一个小应用程序:


  • 有两个按钮和一个简单的消息的模板

  • 由一个名为spice的字符串组成的模型

  • 具有设置香料价值的两个功能的控制器

我们的模板中的消息包含对香料模型的绑定,默认情况下,它设置为字符串“very”。 根据单击哪个按钮,香料模型设置为辣椒或jalapeño,并且消息通过数据绑定自动更新。


index.html


 

 

 

The food is {{spice}} spicy!


app.js


var myApp = angular.module('spicyApp1', []);

myApp.controller('SpicyController', ['$scope', function($scope) {

    $scope.spice = 'very';

    $scope.chiliSpicy = function() {

        $scope.spice = 'chili';

    };

    $scope.jalapenoSpicy = function() {

        $scope.spice = 'jalapeño';

    };

}]);

在上面的例子注意事项:


  • ng-controller指令用于(隐式地)为模板创建范围,并且scope由SpicyController控制器扩充(管理)。

  • SpicyController只是一个纯JavaScript函数。 作为(可选)命名约定,名称以大写字母开头,以"Controller"结尾。

  • 将属性分配给$scope创建或更新模型。

  • 控制器方法可以通过直接赋值到scope来创建(参见chiliSpicy方法)

  • Controller方法和属性在模板中可用(对于

    元素及其子元素)。


    参数示例

    控制器方法也可以接受参数,如前面示例的以下变体所示。


    index.html


     

     

     

     

    The food is {{spice}} spicy!


    app.js


    var myApp = angular.module('spicyApp2', []);

    myApp.controller('SpicyController', ['$scope', function($scope) {

        $scope.customSpice = 'wasabi';

        $scope.spice = 'very';

        $scope.spicy = function(spice) {

            $scope.spice = spice;

        };

    }]);

    SpicyController控制器现在只定义一个名为spicy的方法,它接受一个名为spice的参数。 模板然后引用此Controller方法,并在第一个按钮的绑定中传递字符串常量“chili”,并在第二个按钮中传递模型属性customSpice(绑定到输入框)。

    scope继承示例

    通常将控制器附加在DOM层次结构的不同级别。 由于ng-controller指令创建了一个新的子范围,我们得到了一个继承的范围的层次结构。 每个控制器接收的$scope将可以访问由层次结构中较高的控制器定义的属性和方法。


    index.html


     

       

    Good {{timeOfDay}}, {{name}}!


       

         

    Good {{timeOfDay}}, {{name}}!


         

           

    Good {{timeOfDay}}, {{name}}!

         

       

     


    app.css


    div.spicy div {

      padding: 10px;

      border: solid 2px blue;

    }


    app.js


    var myApp = angular.module('scopeInheritance', []);

    myApp.controller('MainController', ['$scope', function($scope) {

      $scope.timeOfDay = 'morning';

      $scope.name = 'Nikki';

    }]);

    myApp.controller('ChildController', ['$scope', function($scope) {

      $scope.name = 'Mattie';

    }]);

    myApp.controller('GrandChildController', ['$scope', function($scope) {

      $scope.timeOfDay = 'evening';

      $scope.name = 'Gingerbread Baby';

    }]);

    注意我们如何在模板中嵌套三个ng-controller指令。 这将导致为我们的视图创建四个范围:


    • rootscope(根作用域)

    • MainController scope,其中包含timeOfDay和name属性

    • ChildController scope,它继承timeOfDay属性,但覆盖(阴影)来自上一个scope的name属性

    • GrandChildController scope,它覆盖(阴影)在MainController中定义的timeOfDay属性和在ChildController中定义的name属性

    继承以与对属性的方式相同的方式处理方法。 所以在我们以前的例子中,所有的属性都可以替换为返回字符串值的方法。

    测试控制器

    虽然有很多方法来测试一个控制器,最好的约定之一,如下所示,涉及注入$rootScope和$controller:


    控制器定义:

    var myApp = angular.module('myApp',[]);

    myApp.controller('MyController', function($scope) {

      $scope.spices = [{"name":"pasilla", "spiciness":"mild"},

                       {"name":"jalapeno", "spiciness":"hot hot hot!"},

                       {"name":"habanero", "spiciness":"LAVA HOT!!"}];

      $scope.spice = "habanero";

    });

    控制器测试

    describe('myController function', function() {

      describe('myController', function() {

        var $scope;

        beforeEach(module('myApp'));

        beforeEach(inject(function($rootScope, $controller) {

          $scope = $rootScope.$new();

          $controller('MyController', {$scope: $scope});

        }));

        it('should create "spices" model with 3 spices', function() {

          expect($scope.spices.length).toBe(3);

        });

        it('should set the default value of spice', function() {

          expect($scope.spice).toBe('habanero');

        });

      });

    });

    如果需要测试嵌套的控制器,则必须在DOM中存在的测试中创建相同的作用域层次结构:


    describe('state', function() {

        var mainScope, childScope, grandChildScope;

        beforeEach(module('myApp'));

        beforeEach(inject(function($rootScope, $controller) {

            mainScope = $rootScope.$new();

            $controller('MainController', {$scope: mainScope});

            childScope = mainScope.$new();

            $controller('ChildController', {$scope: childScope});

            grandChildScope = childScope.$new();

            $controller('GrandChildController', {$scope: grandChildScope});

        }));

        it('should have over and selected', function() {

            expect(mainScope.timeOfDay).toBe('morning');

            expect(mainScope.name).toBe('Nikki');

            expect(childScope.timeOfDay).toBe('morning');

            expect(childScope.name).toBe('Mattie');

            expect(grandChildScope.timeOfDay).toBe('evening');

            expect(grandChildScope.name).toBe('Gingerbread Baby');

        });

    });


    转自: https://segmentfault.com/a/1190000008446694

    作者: jxycbjhc


    >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>


    ==========阅读原文==========