Angular 2 JavaScript/ES5 教程 - 第一部分至第三部分





5.00/5 (3投票s)
本文介绍 Angular 2 教程“英雄之旅”的 JavaScript (ECMAScript 5) 版本。学习如何在 JavaScript/ES5 中实现 TypeScript 示例。本文涵盖了原教程的第一、第二和第三部分。
为 Angular 2 (版本 2.0.0-beta7) 编写。 可能适用于其他版本。
引言
Angular 2 于 2015 年 12 月从开发预览版转为测试版。作为目前最常用的单页 Web 应用程序框架之一 AngularJS 的可能继任者,许多 UI 和 Web 开发人员如今都密切关注 Angular 2 的潜力和可能性。
许多 Web 开发人员熟悉当今的 JavaScript,通常是 ECMAScript 5 版本。这尤其适用于熟悉 AngularJS 的开发人员,因为 AngularJS 是在该语言中开发并最常用该语言进行消费的。另一方面,Angular 2 是用 TypeScript 编写的,并且设计为在 TypeScript、JavaScript 或 Dart 中使用。
Angular 2 附带丰富的文档,供开发人员入门。 angular.io 提供了三个面向初学者的部分:
- 一个 5 分钟快速入门 [^],涵盖了设置文件和文件夹结构、实现 (空) Angular 2 组件以及在浏览器中运行它的基本知识。
- 一个 五步教程 [^],展示了 Angular 2 的基本机制,如控制器、指令、多个组件、依赖注入和路由。
- 一个 开发人员指南 [^],深入涵盖了这些以及更多主题。
由于 Angular 2 本身是用 TypeScript 编写的,因此大部分文档和示例都提供 TypeScript 版本。但是,如果您开始寻找 JavaScript 或 Dart 版本,选项就会变得稀少。只有快速入门和开发人员指南的部分内容提供所有三种语言的版本。当 Angular 2 从测试版变为正式版时,这种情况可能会改变。但目前 JavaScript 文档非常少。
当我完成这个快速入门示例时,官方教程是下一步的显而易见的选择。您可以在这里找到官方的 Angular 2 TypeScript 教程: 教程:英雄之旅 - ts [^]
本文的目的是提供该教程的 JavaScript 版本,并可能解释一些使其能够运行的必要工作。由于 TypeScript 会被转译成 JavaScript,因此这是可能的,但并不总是完全显而易见的。我们将重点关注已转译成 JavaScript / ES5 的特定于 TypeScript 的主题,而主要跳过涉及布局 (主要是 HTML) 或样式 (主要是 CSS) 的部分。
由于始终伴随可运行的源代码来理解解释更容易,因此您可以在本文中找到我为每个部分编写的 JavaScript 示例项目。
TypeScript / JavaScript
我想在此说清楚。TypeScript 绝对有其优势和潜力,并且可以成为设置新应用程序的绝佳选择,尤其是在基于 Angular 2 的情况下。所以本文并非对 TypeScript 的贬低。本文面向今天正在使用 JavaScript 编写 AngularJS 应用程序的开发人员,他们希望快速了解 Angular 2 或将其与 AngularJS 进行比较,而无需在底层语言上纠结。
介绍完毕,开始编码……
Using the Code
第 0 部分 - 带空组件的应用
本教程从 Angular 2 快速入门的结尾开始。由于这一部分有 JavaScript 版本,我建议我们先从那里开始,等快速入门示例运行起来后再回来。
https://angular.io/docs/js/latest/quickstart.html
然后,我们有一个带有空类的组件,它在 Angular 2 应用程序中被引导。在浏览器中,这应该看起来像右侧的截图。
第 1 部分 - 类和属性 (又名英雄编辑器)
第 1 部分使用 TypeScript 设置了一个带有构造函数和两个 `public` 属性的类。其中一个属性公开了一个自定义类型 `Hero`。
公共属性
本节的第一个任务是为 `AppComponent` 类创建两个 `public` 属性 `title` 和 `hero`。在 TypeScript 中,看起来是这样的:
// AppComponent class (TS)
export class AppComponent {
public title = 'Tour of Heroes';
public hero = 'Windstorm';
}
在 JavaScript 中,向对象添加 `public` 属性的直接方法是在构造函数中定义和公开它们:
// AppComponent constructor (JS)
constructor: function () {
this.title = 'Tour of Heroes';
this.hero = new Hero(1, 'Windstorm');
}
接口
接下来,我们将 `hero` 属性的类型从 `string` 更改为自定义接口。在 TypeScript 中,我们首先定义 `Hero` 类型。
// Hero interface (TS)
interface Hero {
id: number;
name: string;
}
然后,我们可以在 `hero` 属性中使用它。
// Hero property (TS)
public hero: Hero = {
id: 1,
name: 'Windstorm'
};
接口在 JavaScript 中是什么样的?教程说:“将类转译成 JavaScript 会生成代码。将接口转译只会生成——什么也没有。” 如果您查看转译后的 JS 代码,我们会发现只有一个普通的 JavaScript 对象。关于 `Hero` 类型或 `id` 和 `name` 属性的信息在转译过程中丢失了。所以这就是我们添加到 `hero` 属性的内容:
// hero property (js)
this.hero = {
id: 1,
name: 'Windstorm'
};
结果
第 1 部分的其余部分涵盖了一些 HTML 布局,我们在这里省略了。最终结果应该看起来像侧面的截图。编辑文本框中的姓名,看看数据绑定如何刷新 (第二级) 标题。
第 2 部分 - 列表、DOM 操作和样式 (又名主/详细)
教程的第 2 部分涵盖了大量关于 DOM 操作、如何插入或删除元素的内容。对于 JavaScript 部分,我们添加了一个新函数并从视图中访问它。
变量
var HEREOS
是一个普通变量。在 JavaScript 中,只需删除类型说明符。教程将变量插入到 TypeScript 文件的底部。如果您使用 eslint (或类似的样式检查器),我们会将其添加到 JavaScript 文件的顶部。
*ngFor
下一段从控制器创建了一个包含重复项的列表。如果您熟悉 AngularJS,请看看 `ng-repeat` 在 Angular 2 中是如何变成 `*ngFor` 的。
属性可以动态添加
HTML 代码绑定到模型中的 `selectedHero` 变量。在 TypeScript 中,我们必须将其显式设置为 `public` 属性。在 JavaScript 中,当 `selectedHero` 属性第一次由 `onSelect` 函数 (下一段) 设置时,它将被添加到我们的对象中。由于我们没有设置初始值,因此目前不需要定义此变量。
原型函数
TypeScript 的 `onSelect` 处理程序看起来像这样:
// onSelect (ts)
onSelect(hero: Hero) {
this.selectedHero = hero;
}
在 JavaScript 中最简单的实现可能是构造函数中的另一个 `public` 属性:
// onSelect as public property (js)
constructor: function () {
// ...
this.onSelect = function(hero) {
this.selectedHero = hero;
};
}
如果我们想使用 JavaScript 原型,我们可以在 `prototype` 上定义该函数。这可以在构造函数外部直接完成。
// onSelect as prototype property (js)
app.AppComponent.prototype.onSelect = function (hero) {
this.selectedHero = hero;
};
结果
同样,HTML 和 CSS 中还有更多任务要做。您可以仔细查看 `ngIf`,这是 Angular 2 中的另一个典型 Angular 功能。完成第 2 部分后,应用程序应该会显示一个样式化的列表和一个编辑器区域。
第 3 部分 - 多个组件
到目前为止,我们 (小) 应用程序是由一个独立的块 (单体) 组成的。在第 3 部分,我们将通过添加第二个 Angular 组件来为我们的应用程序添加基本模块化。
添加第二个组件
我们将创建一个 `hero-detail.js` 文件,而不是 `hero-detail.ts`。新组件的名称是 `HeroDetailComponent`。由于我们已经知道如何创建组件,因此这一部分相对简单。JavaScript 代码应该看起来像这样:
// hero-detail.js
app.HeroDetailComponent = ng.core
.Component({
selector: 'my-hero-detail',
})
.Class({
constructor: function () {}
});
别忘了在 `index.html` 中加载新的 JS 文件。
<!-- index.html -->
<script src='app/hero-detail.js'></script>
定义数据绑定的输入
我们希望 `hero` 属性在 Angular 的变更检测中被更新。因此,我们将它标记为输入。与 TypeScript 代码类似,我们在 `HeroDetailComponent` 的 `Component` 定义中注册 `inputs: ['hero']`。
定义指令
TypeScript 使用语句 `import {HeroDetailComponent}` 从 `./hero-detail.component';` 导入 `HeroDetailComponent`。因此,该指令可以被引用为 `HeroDetailComponent` 而无需进一步解析。
// app.ts
import {HeroDetailComponent} from './hero-detail.component';
@Component({
// ...
directives: [HeroDetailComponent]
// ...
})
由于 JavaScript 中缺少此 `import` 语句,我们必须从我们的 Angular `app` 中解析该指令。
directives: [app.HeroDetailComponent]
现在应用程序应该可以再次运行了。
结果
在第 3 部分,我们拆分了 `AppComponent` 并提取了 `HeroDetailComponent`。我们可以在右侧的截图中找到新的文件结构。尽管如此,UI 仍然看起来像第 2 部分。
工具和资源
以下是一些帮助指引方向的辅助工具:
- Angular 2 API 文档/预览: https://angular.io/docs/ts/latest/api/
- 将 TypeScript 示例转译成 JavaScript
- 浏览器的控制台输出
总结
这是本系列的第一篇文章。我们已经创建了一个带有两个组件的小型 Angular 2 应用程序。在第二篇文章中,我们将创建一个服务来模拟与服务器后端通信,引入依赖注入,并使用路由器在多个视图之间导航。
您可以在这里找到第二篇文章: Angular 2 JavaScript/ES5 教程 - 第四部分和第五部分 [^]
您对 Angular 2 的初步体验如何,尤其是在与 JavaScript/ES5 结合使用时?您尝试过不同的方法吗?您是否能够为某些方面找出更简单的解决方案,或者我错过了什么?请在下面的评论中告诉我。
历史
- 2016 年 2 月 28 日:第一篇文章 (第 1 部分至第 3 部分) 的初始版本
- 2016 年 3 月 5 日:指向第二篇文章 (第 4 部分至第 5 部分) 的引用, minor changes
许可证
原始教程,特别是源代码文件,根据 MIT 风格的许可证发布,该许可证可以在 http://angular.io/license 的 LICENSE 文件中找到。本教程和源代码修改根据 MIT 许可证发布,该许可证可以在 https://open-source.org.cn/licenses/MIT 找到。