带有 ng-Controller 示例的 AngularJS 控制器

⚡ 智能摘要

AngularJS 中的控制器承载着屏幕的业务逻辑。它通过作用域对象接收数据,处理数据,并将结果返回给视图。ping 不包含应用程序逻辑的演示标记。

  • 🎯 核心职责: 控制器填充作用域对象并向视图公开方法;它不操作 DOM。
  • 🔗 接线: ng-controller 指令将一个命名控制器绑定到一个元素,使该元素及其子元素能够访问控制器作用域。
  • 🔁 双向装订: ng-model 将表单字段链接到作用域属性,因此视图中的编辑会更新控制器,反之亦然。
  • 🧩 方法: 附加到作用域的函数将不同的逻辑部分分隔开来,可以直接从视图表达式中调用。
  • 🏷️ controllerAs 语法: 给控制器设别名并绑定到 this 消除控制器相互嵌套时的歧义。
  • 📁 分离: 将控制器移到专用的 app.js 文件中,可以使视图层与逻辑层保持独立。

使用 ng-controller 的 AngularJS 控制器

AngularJS 中的控制器是什么?

A 控制器 在 AngularJS 中,控制器从视图获取数据,处理数据,然后将处理后的数据发送给最终用户显示的视图。控制器则承载着核心业务逻辑。它使用数据模型,执行必要的处理,然后将输出传递给视图。

⚠️ 版本说明: AngularJS(1.x 分支)已于 2021 年 12 月 31 日停止维护,不再接收任何安全补丁。以下概念仍然适用于旧版应用程序;在现代 Angular 中,相同的功能由组件类而非控制器来实现。

了解了控制器是什么之后,还有一个问题悬而未决:它究竟是如何与视图通信的?下一节将解答这个问题。

从Angular的角度来看,控制器做了什么

以下是对AngularJS控制器工作原理的简单定义:

AngularJS 控制器的工作原理
AngularJS 控制器的工作原理
  • 控制器的主要职责是控制传递给视图的数据。范围和视图具有双向通信。
  • 视图属性和事件可以调用作用域内的函数。以下代码片段展示了这一点。 函数($scope) 声明的控制器加上一个返回的内部函数 $scope.firstName$scope.lastName 加入。 AngularJS定义为变量的函数就是方法。

AngularJS 控制器的工作原理

  • 数据从控制器传递到作用域,然后在作用域和视图之间来回传递。
  • 作用域将模型暴露给视图。可以通过作用域上定义的方法修改模型,这些方法由视图中的事件触发。
  • 控制器不应该用于操作 DOM。那是 DOM 操作者的工作。 指令.
  • 最佳实践是根据功能创建控制器。例如,如果某个输入表单需要控制器,则创建一个名为“表单控制器”的控制器。

了解了该机制之后,下一节将从空白页面开始构建控制器。

如何在 AngularJS 中构建基本控制器

以下是在AngularJS中创建控制器的步骤。

步骤 1)创建一个基本的 HTML 页面

在创建控制器之前,必须先创建基本的 HTML 页面。以下代码片段是一个名为“活动注册”的简单页面,其中引用了…… Bootstrap 以及 AngularJS。

在 AngularJS 中构建基本控制器

  1. 引用 Bootstrap CSS样式表,与以下方式一起使用: Bootstrap 图书馆。
  2. 这是对 AngularJS 库的引用。从此以后所有与 AngularJS 相关的操作都将通过此文件进行解析。
  3. 对的参考 Bootstrap 该库使某些控件具有响应性。

⚠️ 更正: 原帖加载了 jQuery 并声称 AngularJS 依赖于它。但实际上并非如此。AngularJS 自带 jqLit​​e,它是 jQuery API 的一个内置子集,只有在 jQuery 加载成功时才会升级到完整的 jQuery。 before 引用已被删除。

步骤 2)检查文件和文件结构

在 AngularJS 中构建基本控制器

  1. 文件像任何传统的 Web 应用程序一样,分为两个文件夹:“css”用于样式表,“lib”用于其他文件。 JavaScript 文件。
  2. bootstrap.css 文件位于 css 文件夹中,它决定了网站的外观和风格。
  3. angular.js 是主要库,从 AngularJS 网站下载并保存在 lib 目录中。
  4. app.js 文件将包含控制器的代码。

步骤 3)使用 AngularJS 代码显示输出

这里的目标是在浏览器中打开页面时,将“AngularJS”字样以纯文本和文本框的形式显示出来。

在 AngularJS 中构建基本控制器

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Event Registration</title>
<link rel="stylesheet" href="css/bootstrap.css">
</head>
<body>
<h1> Guru99 Global Event</h1>

<div ng-app="DemoApp" ng-controller="DemoController">
Tutorial Name : <input type="text" ng-model="tutorialName"><br>
This tutorial is {{tutorialName}}
</div>

<script src="lib/angular.js"></script>
<script>
var app = angular.module('DemoApp', []);

app.controller('DemoController', ['$scope', function($scope) {
  $scope.tutorialName = "AngularJS";
}]);
</script>
</body>
</html>

Code 说明:

  1. ng-应用程序 此元素被标记为 AngularJS 应用程序的根元素。以 `<a>` 为前缀的属性 ng- 这些都是内置指令。“DemoApp”是应用程序的名称。
  2. 该div承载 ng-控制器 命名为“DemoController”,这使得该元素及其内部的所有内容都可以访问控制器作用域。
  3. ng模型 创建模型绑定,将“教程名称”文本框绑定到作用域属性。 tutorialName.
  4. 模块 DemoApp 创建后,控制器会为其分配默认值“AngularJS”。 tutorialName.

⚠️ 已进行更正。 原清单声明 chrset="UTF 8"这既不是有效的属性,也不是有效的编码名称,并且 AngularJS 加载了两次——一次是从 CDN,一次是从…… lib/angular.js两次加载库会重新注册模块系统,从而导致不可预测的行为。依赖数组注解 ['$scope', function($scope){…}] 此外还添加了该功能,如果没有该功能,控制器会在文件被压缩时立即崩溃。

输出:

在 AngularJS 中构建基本控制器

计划 tutorialName 被赋值为“AngularJS”,该值会显示在文本框和纯文本行中。单个属性足以进行演示;实际的控制器通常还会暴露其他行为,下一节将对此进行介绍。

如何在 AngularJS 控制器中定义方法

通常情况下,控制器中会定义多个方法来分离业务逻辑。例如,如果控制器需要将两个数字相加并求和,则需要定义多个方法。trac如果是两个数字运算,则需要为每个运算创建一个方法。

下面的示例定义了 AngularJS 控制器中的一个自定义方法,该方法返回一个字符串。

在 AngularJS 控制器中定义方法

<!-- The head and library references are unchanged from Step 3 -->
<div ng-app="DemoApp" ng-controller="DemoController">
Tutorial Name : <input type="text" ng-model="tutorialName"><br>
This tutorial is {{tName()}}
</div>

<script>
var app = angular.module('DemoApp', []);

app.controller('DemoController', ['$scope', function($scope) {
  $scope.tutorialName = "AngularJS";

  // A method on the scope, callable from the view as tName()
  $scope.tName = function() {
    return $scope.tutorialName;
  };
}]);
</script>

Code 说明:

  1. 函数作为成员附加到作用域对象。 tName它返回当前值 tutorialName.
  2. 该视图调用该方法 {{tName()}}括号很重要:如果没有括号,表达式将打印函数本身而不是其结果。

⚠️ 更正: 原始方法读 $scope.tName = function() { return $scope.tName; };该函数返回的是自身,而不是教程名称,因此页面渲染的是函数体而不是文本。现在它返回的是自身。 $scope.tutorialName.

输出:

在 AngularJS 控制器中定义方法

目前为止,所有内容都放在同一个文件中。生产应用程序则将控制器分开存放,下一节将对此进行演示。

带有 ng-Controller 示例的 AngularJS 控制器

上面的“HelloWorld”示例将所有功能都放在了一个文件中。现在需要将控制器代码移到单独的文件中。

步骤1) 在 app.js 文件中,为您的控制器添加以下代码。

带有 ng-Controller 的 AngularJS 控制器

angular.module('app', [])
  .controller('HelloWorldCtrl', ['$scope', function($scope) {
    $scope.message = "Hello World";
  }]);

上面的代码执行以下操作:

  1. 定义一个名为“app”的模块,其中包含控制器。
  2. 创建一个名为“HelloWorldCtrl”的控制器,该控制器显示“Hello World”消息。
  3. 使用作用域对象将信息从控制器传递到视图,在本例中,信息是一个名为 `<variable_name>` 的变量。 message.

步骤2) 在 Sample.html 中,添加一个带有 ng-controller 指令和对成员变量引用的 div 元素。 message请记住引用 app.js 文件,其中包含控制器源代码。

带有 ng-Controller 的 AngularJS 控制器

<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="UTF-8">
<title>Event Registration</title>
<link rel="stylesheet" href="css/bootstrap.css">
</head>
<body>
<h1> Guru99 Global Event</h1>
<div class="container">
<div ng-controller="HelloWorldCtrl">{{message}}</div>
</div>

<script src="lib/angular.js"></script>
<script src="app.js"></script>
</body>
</html>

⚠️ 更正: 必须加载 app.js 文件 angular.js,因为它调用了 angular.module原版程序也加载了两次库,并且携带了相同的内容。 chrset 错字。

输出:

带有 ng-Controller 的 AngularJS 控制器

到目前为止,每个示例都直接读取和写入了属性。 $scope以下部分介绍了AngularJS团队推荐的替代方案。

如何在AngularJS中使用controllerAs语法

直接结合 $scope 这种方法可行,但一旦控制器嵌套,就会产生歧义。例如,视图表达式可以这样写: {{name}} 没有提供任何关于哪个控制器拥有该控制器的线索。 name而且,由于子作用域在原型上继承自父作用域,因此写入继承的原始类型的嵌套控制器会在后台静默创建自己的影子副本。 controllerAs 通过给每个控制器赋予别名,语法可以消除这两个问题。

步骤1) 使用别名在视图中为控制器命名 as 关键字,然后在每个绑定前加上该别名。

步骤2) 在控制器内部,将属性附加到 this 而不是 $scope.

<div ng-controller="DemoController as demo">
Tutorial Name : <input type="text" ng-model="demo.tutorialName">
This tutorial is {{demo.tutorialName}}
</div>

<script>
app.controller('DemoController', function() {
  // 'vm' is captured so nested functions keep the right reference
  var vm = this;
  vm.tutorialName = "AngularJS";

  vm.tName = function() {
    return vm.tutorialName;
  };
});
</script>

接下来有三项好处。装订方式变得具有自我记录功能,因为 demo.tutorialName 命名其所有者。嵌套控制器不再发生冲突,因为父控制器已别名化。 outer 以及一个化名的孩子 inner 两者都可以暴露 name值也通过对象而不是原始基本类型进行绑定,绕过此限制。ping 子版本中的编辑操作永远不会同步到父版本,这是一种陷阱。

👍 提示: 捕获 this 存入一个变量,例如 vm 在控制器顶部。在回调函数内部, this 指的是完全不同的东西,并且捕获的引用保持绑定正确。

选择绑定风格是一回事,决定控制器中究竟应该包含哪些内容则是另一回事,下面的比较将阐明这两者之间的界限。

AngularJS 中的控制器与服务

初学者经常会把本应由服务完成的工作放到控制器中。区别在于生命周期和可重用性:控制器仅在其视图显示在屏幕上时存在,而服务是单例模式,其生命周期与应用程序的生命周期相同。

方面 控制器 业务
终身版 创造与毁灭皆源于此景 整个应用程序使用单个实例
目的 准备一个视图的数据 共享逻辑、状态和服务器调用
可重复使用 不,这与它的观点有关。 是的,可注射于任何部位
在视图之间保持状态 不,导航过程中状态丢失了。 是的,状态持续存在。
典型内容 作用域属性和视图方法 HTTP 调用、缓存、业务规则

保持控制器简洁。如果两个控制器需要相同的逻辑,或者某个值需要在视图之间切换时仍然有效,请将其移至服务中,并在需要的地方注入该服务。一个实用的测试方法是:关闭当前屏幕后,代码是否仍然有意义?如果答案是肯定的,那么它就应该放在服务中。

常见问题

是的。AngularJS 会为每个带有指令的元素创建一个独立的实例和一个独立的作用域。这些实例之间没有共享状态,因此在一个实例中发生的更改不会反映在另一个实例中。

当控制器属于由……加载的整个视图时,在路由中声明它。 路由对于无论当前路由如何都显示在页面内的组件,请使用 ng-controller。切勿同时声明两者,否则控制器会运行两次。

使用数组注解,在函数前以字符串形式列出依赖项名称。代码压缩器会重命名函数参数,但不会重命名字符串字面量,因此注入器仍然可以正确解析 $scope 和所有服务。

是的。 AI 助手会根据屏幕的简单描述生成模块、控制器和作用域绑定。务必检查依赖项注解,因为生成的代码经常会遗漏它。

AI 工具将作用域分配重写为捕获的 vm 变量的属性,并在每个匹配的视图绑定前加上别名。 Rev手动查看 $watch 调用和事件监听器,因为它们仍然需要作用域对象。

总结一下这篇文章: