AngularJS控制器

前面我们讲解了如何创建模块,但是拿他们来干什么呢?到目前为止它们只是空模块。

现在让我们讲解控制器。控制器在AngularJS中是干粗活的,使用JavaScript函数执行大部分用户界面之类的工作。在AngularJS应用程序中控制器的一些共同职责包括:

  • 从服务器为当前的用户界面获取正确的数据
  • 决定显示给用户哪部分数据
  • 表示层逻辑:比如怎样显示元素、显示用户界面的哪些部分、怎样给它们设置样式等。
  • 用户交互:比如当用户点击会如何响应、应该怎样验证输入文本。

AngularJS控制器几乎总是直接连接一个视图或HTML。从来没有哪个控制器中不用于用户界面(这种业务逻辑适用于服务),它建立起模型(驱动应用程序的的数据)与视图(用户看到的交互的)之间的通道。

让我们来看一看如何为notesApp模块创建一个控制器:

<!DOCTYPE html>
<html ng-app="notesApp">
<head>
  <title>Hello AngularJS</title>
</head>
<body ng-controller="MainCtrl">
Hello {{1 + 1}}nd time AngularJS
<script src="https://cdn.jsdelivr.net/angularjs/1.2.28/angular.min.js"></script>
<script type="text/javascript">
  angular.module('notesApp', [])
    .controller('MainCtrl', [function() {
      // Controller specific code goes here
      console.log('MainCtrl has been created');
    }]);
</script>
</body>
</html>

点击此处查看效果

我们使用AngularJS模块暴露的controller方法定义了一个控制器。controller方法的第一个参数表示控制器名称,上面例子中创造性地将其命名为MainCtrl。 第二个参数是控制器的实际定义,表示它做什么以及如何做。

此处有一个令人稍微费解的地方,即数组表示法。注意,我们在数组内部定义了控制器函数。也就是说,模块上的控制器函数的第一个参数表示控制器名称(MainCtrl),第二个参数是一个数组。数组由控制器的所有依赖项的字符串变量构成,数组中的最后一个参数是实际的控制器函数。在这种情况下,因为没有依赖关系,函数是数组中唯一的参数,该参数包含所有控制器代码。

我们还引入一个新指令,ng-controller。它告诉AngularJS用给定名称去实例化控制器实例,并将其附加到DOM元素上。在这种情况下,AngularJS会加载MainCtrl,最终将打印console.log()语句。

现在,我们将为第一个AngularJS应用使用控制器,将“hello world”消息从HTML移到控制器,从控制器获取并显示它
。 让我们来看一看下面代码:

<!DOCTYPE html>
<html ng-app="notesApp">
<head>
  <title>Notes App</title>
</head>
<body ng-controller="MainCtrl as ctrl">
{{ctrl.message}} AngularJS.
<button ng-click="ctrl.changeMessage()">
  Change Message
</button>
<script src="https://cdn.jsdelivr.net/angularjs/1.2.28/angular.min.js"></script>
<script type="text/javascript">
  angular.module('notesApp', [])
    .controller('MainCtrl', [function () {
      var self = this;
      self.message = 'Hello ';
      self.changeMessage = function () {
        self.message = 'Goodbye ';
      };
    }]);
</script>
</body>
</html>

点击此处查看效果,用户界面应该如下图所示。

Hello world AngularJS controller

是的,我们只看到“Hello AngularJS。 ”用户界面中没有显示“Goodbye”。让我们深入研究这个例子,看看我们能否清楚正在发生什么事情:

  • 正如我们之前看到的我们定义了notesApp模块。
  • 我们使用模块的controller方法创建了名为MainCtrl的控制器。
  • 我们定义了控制器实例的helloMsg(使用this关键字)变量,变量goodbyeMsg作为控制器实例的局部变量(使用var关键字)。
  • 我们通过使用另一个指令:ngcontroller在用户界面中使用该控制器。这个指令允许我们将控制器实例与用户界面元素关联(在本例中的body标记)。
  • 当使用ngcontroller时我们也给MainCtrl实例一个特殊名称,这里我们称之为ctrl。这在AngularJS中被称为controllerAs语法,在HTML中我们可以给每个控制器实例一个名称以识别它们的作用。
  • 然后我们使用双大括号标记将helloMsg和goodbyeMsg变量从控制器关联到HTML。

很明显使用this关键字的定义控制器变量可以从HTML访问,局部变量则不行。

此外,任何控制器实例定义的变量(控制器中使用this, 而不是var关键字声明变量如goodbyeMsg)可以访问并通过HTML显示给用户。基本上就是我们如何从控制器给用户界面注入公开数据和业务逻辑。

用户需要看到HTML需要使用的任何东西,需要使用this来定义。HTML不需要直接访问的任何东西不应该放在这里,应该在控制器范围中将它们保存为本地变量,类似于goodbyeMsg。

在我们深入研究AngularJS是如何工作之前让我们多看一个例子:

<!DOCTYPE html>
<html ng-app="notesApp">
<head>
  <title>Notes App</title>
</head>
<body ng-controller="MainCtrl as ctrl">
{{ctrl.message}} AngularJS.
<button ng-click="ctrl.changeMessage()">
  Change Message
</button>
<script src="https://cdn.jsdelivr.net/angularjs/1.2.28/angular.min.js"></script>
<script type="text/javascript">
  angular.module('notesApp', [])
    .controller('MainCtrl', [function () {
      var self = this;
      self.message = 'Hello ';
      self.changeMessage = function () {
        self.message = 'Goodbye ';
      };
    }]);
</script>
</body>
</html>

点击此处查看效果
与前面的实例相比有什么不同呢?

  • 现在只对ctrl.message变量绑定。
  • 有个标签为“Change Message”的按钮。有一个内置的指令ng-click,我们将一个函数作为其参数。当单击按钮时,ng-click指令评估传递给的它任何表达式。在这种情况下,我们知道AngularJS触发了控制器的changeMessage()函数。
  • 控制器的changeMessage()函数将信息参数值设置成“Goodbye”。
  • 另外,作为良好的实践,我们应避免在指控制器内的this个关键字,使用self代理变量引用this。后面将解释为什么这是推荐的。

我们以“Hello AngularJS”应用开始演示。但我们单击按钮时,文本变为“Goodbye AngularJS。”。这是AngularJS数据绑定的威力。上面实例有几值得注意地方:

  • 我们写的控制器没有直接访问视图或任何需要更新DOM元素,它是纯JavaScript。
  • 当用户点击按钮触发changeMessage函数,没有必要通知更新用户界面,它会自动更新。
  • HTML将部分DOM连接到控制器、函数和变量,而没有其它方式。

这是AngularJS的一个核心原则在起作用。基于数据驱动,“模型即真理”,这意味着AngularJS应用核心应该是操作和修改模型(纯JavaScript),其它重活就让AngularJS来做吧。

不完全译自《AngularJS-Up and Running》。

发表评论