Angular 2 JavaScript/ES5 教程 - 第 4 和 5 部分





5.00/5 (2投票s)
本文介绍“英雄之旅”Angular 2 教程的 JavaScript (ECMAScript 5) 版本。了解如何使用 JavaScript/ES5 实现 TypeScript 示例。本文涵盖了原教程的第 4 部分和第 5 部分。
为 Angular 2 (版本 2.0.0-beta7) 编写。 可能适用于其他版本。
引言
这是本系列的第二篇文章。在第一篇文章中,我们创建了一个带有两个组件的小型 Angular 2 应用程序。在本文中,我们将添加具有依赖注入和路由/导航的服务。
您可以在此处找到第一篇文章: Angular 2 JavaScript/ES5 教程 - 第 1 至 3 部分
使用代码
第 4 部分 - 依赖注入
第 4 部分最重要的方面是将一个服务通过依赖注入传递到我们的 AppComponent 中。
创建要注入的服务
创建服务
对于 HeroService
,我们创建一个名为 hero.service.js 的单独 JavaScript 文件。我们将该对象注册为 app.HeroService
,并从 constructor
开始。下面的代码片段已包含公共 getHeroes()
函数。
// HeroService stub (js)
(function (app) {
app.HeroService = ng.core
.Class({
constructor: function () {
this.getHeroes = function() {
return HEROES;
};
}
});
})(window.app || (window.app = {}));
可注入装饰器
在 TypeScript 中,HeroService
会被 Injectable()
装饰。
// HeroService class (ts)
@Injectable()
export class HeroService {
}
在转译后的 JavaScript 代码中,我们会找到一个对应的语句。但是,如果我们省略它,它似乎对类的行为没有影响。
模拟数组
HeroService
的 getHeroes()
函数返回模拟数据 HEROES
。遵循教程,我们将此数组从 app.js 移到其自己的文件 mock-heroes.js。
在 index.html 中注册脚本
不要忘记在 index.html 中注册新的文件 hero.service.js 和 mock-heroes.js。脚本注册现在应该如下所示。
<!-- script registration in index.html -->
<script src='app/mock-heroes.js'></script>
<script src='app/hero.service.js'></script>
<script src='app/hero-detail.js'></script>
<script src='app/app.js'></script>
<script src='app/main.js'></script>
依赖注入
下一步,我们将 HeroService
注入到 AppComponent
中。为了在 Angular 2 中正确解析依赖项,我们需要执行两个步骤:
注册提供程序
我们将提供程序注册到组件。这对于 TypeScript 和 JavaScript 几乎相同。我们唯一需要更改的是在 providers 属性中直接指定如何从我们的 Angular 应用程序解析 app.HeroService
。
// Provider registration (js)
app.AppComponent = ng.core
.Component({
// ...
providers: [ app.HeroService ]
})
在构造函数中注入服务
这是最棘手的部分。在 TypeScript 中,我们可以通过提供以下详细信息,将提供的实例作为参数注入到构造函数中:
- 访问修饰符
- 变量名
- 变量类型
在我们的例子中,它看起来像这样:
// AppComponent constructor (ts)
constructor(private _heroService: HeroService) { }
乍一看,此代码的 JavaScript 版本并不明显。我们不使用单个函数,而是将构造函数定义为一个数组。该数组包含我们想要注入的每个提供实例的类型,以及作为最后一个元素的构造函数。然后,我们可以将参数传递给构造函数,这些参数将按顺序作为提供的依赖项类型进行解析。
//AppComponent constructor (js)
constructor: [
app.HeroService,
function (heroService) {
this.heroService = heroService;
}
]
请注意,提供的类型和参数名称之间没有关系。如果我们以名为 foo
的构造函数参数注入 app.HeroService
类型,Angular 也完全可以。
使用注入的服务
如果 heroService
是一个公共属性,我们必须将其添加到对象中(例如 this.heroService = heroService);
)。但是,由于我们将对象保持为私有,因此将在以下 getHeroes()
函数中使用构造函数参数 heroService
。
// getHeroes function in AppComponent (js)
this.getHeroes = function() {
this.heroes = heroService.getHeroes();
};
现在应用程序将重新启动。正如您在右侧的屏幕截图中看到的,服务中的英雄将再次列在 AppComponent 中。
使用 Angular 生命周期钩子
当我们的组件经过某个“状态”(例如初始化或销毁)时,在组件中执行函数是一个常见用例。因此,Angular 提供了几个生命周期钩子 [^]。在这种情况下,我们想使用 ngOnInit
钩子来调用 getHeroes()
。
从 OnInit 派生
在 TypeScript 中,我们将实现 OnInit
接口,该接口提供一个 ngOnInit()
函数,Angular 将在相应的生命周期事件期间调用它。严格来说,这是一种继承。因此,我们将通过在对象的原型上提供正确的函数来在 JavaScript 中解决它。
//OnInit implementation in AppComponent (js)
app.HeroListComponent.prototype.ngOnInit =
function () {
this.getHeroes();
};
其他生命周期钩子,如 ngOnChanges
或 ngOnDestroy
,可以使用相同的方式。
使用 Promise
第 4 部分的最后几个步骤涵盖了如何使用 Promise 处理异步结果。这是一个常用的实践,所以您应该仔细研究教程。这里只介绍 heroService
的更改后的函数。
//heroService (js)
this.getHeroes = function () {
return new Promise(resolve =>
setTimeout(() => resolve(HEROES), 2000)
);
};
结果
完成这些步骤后,应用程序将从服务加载英雄。为了模拟远程服务器,响应会被延迟 2 秒。
第 5 部分 - 路由和导航
教程第 5 部分全部关于应用程序中的路由和导航。因此,我们使用 ng.router
包中的 Angular 2 默认路由器。
添加推送 URL 基础
为了在 Web 浏览器中启用客户端导航,我们使用所谓的推送状态。有关此主题,请查看Angular 文档 [^] 和MDN 文档 [^]。在我们的应用程序中,我们在 index.html 中实现了一个 <base href="/">
元素。
<!-- index.html -->
<head>
<base href="/">
如果您在 Angular 2 应用程序中遇到以下异常,很可能是您缺少此行。
EXCEPTION: Error during instantiation of LocationStrategy! (RouterLink -> Router -> Location -> LocationStrategy).
配置路由器
路由器提供程序
在 Angular 2 中,我们需要一个组件来托管路由器。这将是我们的 AppComponent
。为了告诉我们的应用程序如何解析路由器实例,我们引用路由器提供程序 ng.router.ROUTER_PROVIDERS
。
// AppComponent (js)
.Component({
// ...
providers: [ng.router.ROUTER_PROVIDERS, app.HeroService]
})
配置路由
接下来,我们可以通过指定 path
、name
和 component
的类型来配置我们的第一个路由到组件。前两个属性是字符串,最后一个是组件的类型(作为对象)。通过添加 useAsDefault
属性,我们告诉路由器在未选择任何路由时要解析哪个路由。要将路由添加到路由配置,我们会将其作为参数传递给 ng.router.RouterConfig()
。通常我们会一次配置多个路由。因此,RouterConfig()
接受一个数组作为参数。然后我们用这个实例来装饰我们的 AppComponent
。
// AppComponent (js)
app.AppComponent = __decorate([
ng.router.RouteConfig([ {
path: '/heroes',
name: 'Heroes',
component: app.HeroesComponent,
useAsDefault: true
}])
],
app.AppComponent);
代码示例中的 __decorate()
函数是我们从转译的 TypeScript 代码中获得的。不是最易读的部分,但它有效。
使用路由器
我们希望调用路由器链接以在路由状态之间导航。
注册路由器指令
要使用 HTML 中的路由器指令,我们首先需要引用路由器指令。
// AppComponent (js)
.Component({
// ...
directives: [ng.router.ROUTER_DIRECTIVES],
providers: [ng.router.ROUTER_PROVIDERS, app.HeroService]
})
路由器链接和路由器出口
在 JavaScript 中实现这一点后,我们可以在 HTML 中简单地添加 routerLink
和 <router-outlet />
。
<!-- app.html -->
<a [routerLink]="['Heroes']">Heroes</a>
<router-outlet>Heroes</router-outlet>
结果
现在启动应用程序,我们会看到路由器已经导航到我们的英雄组件。请注意浏览器 URL 如何变化。但是,heroes 路由是我们拥有的唯一路由,没有可导航的内容。我们将在下一部分中对此进行更改。
完成教程
添加路由器和配置路由是本部分中最艰巨的任务。现在我们添加一个名为 dashboard 的新组件,并设置 dashboard、hero list 和 hero detail 视图之间的路由。如果您坚持使用原始的 TypeScript 教程,用 JavaScript 实现这一点应该不会太难。您可以在本文中找到我为第 5 部分提供的 JavaScript 解决方案。
结论
通过一点努力,就可以仅使用 JavaScript / ECMAScript 5 设置此应用程序。对于 Angular 2 的初步尝试,没有必要深入研究 TypeScript,尽管为了理解文档和提示,确实需要一些 TypeScript 知识。如果我事先知道这些步骤,我就可以节省大量研究、调试和尝试的时间。
您在 Angular 2 方面的首次体验如何,特别是与 JavaScript/ES5 结合使用时?您尝试过不同的方法吗?您是否找到了某些方面的更简单解决方案,或者我遗漏了什么?请在下面的评论中告诉我。
历史
- 2016年3月5日:初始版本
许可证
原始教程,特别是源代码文件,已根据 MIT 风格的许可证发布,该许可证可在 http://angular.io/license 的 LICENSE 文件中找到。本教程和源代码修改根据 MIT 许可证发布,该许可证可在 https://open-source.org.cn/licenses/MIT 中找到。