详解Angular的8个主要构造块


Posted in Javascript onJune 20, 2017

Angular 主要分为八大构造块(也就是八个核心概念):模块 (module)、组件 (component)、模板 (template)、元数据 (metadata)、数据绑定 (data binding)、指令 (directive)、服务 (service)、依赖注入 (dependency injection)。其中,最核心的一个概念就就组件。

1. 模块 (module)

Angular 应用是模块化的,并且 Angular 有自己的模块系统,它被称为 Angular 模块或 NgModules。

每个Angular应用至少有一个模块(根模块),习惯上命名为AppModule。

根模块在一些小型应用中可能是唯一的模块,大多数应用会有很多特性模块,每个模块都是一个内聚的代码块专注于某个应用领域、工作流或紧密相关的功能。

Angular 模块(无论是根模块还是特性模块)都是一个带有@NgModule装饰器的类。

下面是一个简单的根模块:

// src/app/app.module.ts

import { NgModule }   from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
@NgModule({
 imports:   [ BrowserModule ],
 providers:  [ Logger ],
 declarations: [ AppComponent ],
 exports:   [ AppComponent ],
 bootstrap:  [ AppComponent ]
})
export class AppModule { }

其中重要的属性是:

  1. declarations - 声明本模块中拥有的视图类。Angular 有三种视图类:组件、指令、管道;
  2. exports - declarations 的子集,可用于其它模块的组件;
  3. imports - 本模块声明的组件模板需要的类所在的其它模块。用来导入其他自定义模块,第三方插件模块;
  4. providers - 服务的创建者,并加入到全局服务列表中,可用于应用任何部分;
  5. bootstrap - 指定应用的主视图(称为根组件),它是所有其它视图的宿主。只有根模块才能设置bootstrap属性。通常在main.ts中引导AppModule,这样platformBrowserDynamic().bootstrapModule(AppModule)

2. 组件 (component)

组件负责控制屏幕上的一小块区域,我们称之为视图。

下面是一个组件的简单例子:

// src/app/hero-list.component.ts

export class HeroListComponent implements OnInit {
 heroes: Hero[];
 selectedHero: Hero;

 constructor(private service: HeroService) { }

 ngOnInit() {
  this.heroes = this.service.getHeroes();
 }

 selectHero(hero: Hero) { this.selectedHero = hero; }
}

3. 模板 (template)

模板就是HTML文件,但是不是标准的HTML文件,它使用了一些模板语法,模板语法使模板有了自己的逻辑关系,并能够实现和组件的简单数据交互。

下面是一个简单的模板:

// src/app/hero-list.component.html

<h2>Hero List</h2>
<p><i>Pick a hero from the list</i></p>
<ul>
 <li *ngFor="let hero of heroes" (click)="selectHero(hero)">
  {{hero.name}}
 </li>
</ul>
<hero-detail *ngIf="selectedHero" [hero]="selectedHero"></hero-detail>

通常使用ng g component my-comoponent命令产生一个组件包含四个文件:

my-comoponent.css      // 样式文件
my-comoponent.thml      // 模板
my-comoponent.spec.ts    // 测试文件
my-comoponent.ts      // 这是组件? 通常我们认为这四个文件组成一个组件

4. 元数据 (metadata)

元数据告诉你如何处理一个类。

其实,在Angular中每个组件只是一个类,但是我们可以通过装饰器来附加元数据告诉Angular这是一个组件。

下面就是HeroListComponent的一些元数据。

// src/app/hero-list.component.ts (metadata)

@Component({  // @Component 将后面的 HeroListComponent 类标记为一个组件
 selector:  'hero-list',
 templateUrl: './hero-list.component.html',
 providers: [ HeroService ]
})
export class HeroListComponent implements OnInit {
/* . . . */
}

@Component装饰器能接受一个配置对象, Angular 会基于这些信息创建和展示组件及其视图。

@Component的配置项包括:

  1. selector: CSS选择器,它告诉Angular在父级HTML中查找<hero-list>标签,创建并插入该组件。 例如,如果应用的HTML 包含<hero-list></hero-list>, Angular就会把HeroListComponent的一个实例插入到这个标签中;
  2. templateUrl:组件HTML 模板的模块相对地址;
  3. providers - 组件所需服务的依赖注入提供商数组。 这是在告诉 Angular:该组件的构造函数需要一个HeroService服务,这样组件就可以从服务中获得英雄数据。

到这里你应该可以明白:模板、元数据和组件共同描绘出这个视图。

5. 数据绑定 (databinding)

数据绑定是Angular中最常用的数据处理模式。数据绑定在模板与对应组件的交互中扮演了重要的角色,在父组件与子组件的通讯中也同样重要。

下面是一个简单的例子:

// src/app/hero-list.component.html 

<li>{{hero.name}}</li>
<hero-detail [hero]="selectedHero"></hero-detail>
<li (click)="selectHero(hero)"></li>
  1. {{hero.name}}插值表达式在<li>标签中显示组件的hero.name属性的值;
  2. [hero]属性绑定把父组件HeroListComponent的selectedHero的值传到子组件HeroDetailComponent的hero属性中;
  3. (click) 事件绑定在用户点击英雄的名字时调用组件的selectHero方法。

Angular默认没有双向绑定,但是,官方推荐这样来实现双向绑定:

<input [(ngModel)]="hero.name">

Angular 在每个 JavaScript 事件循环中处理所有的数据绑定,它会从组件树的根部开始,递归处理全部子组件。

6. 指令 (directive)

由于Angular模板是动态的,所以你需要通过指令实现对DOM的转换。(组件是一个带模板的指令;@Component装饰器实际上就是一个@Directive装饰器,只是扩展了一些面向模板的特性。 )

指令分为两种:结构指令、属性指令。

a. 结构指令: 通过在 DOM 中添加、移除和替换元素来修改布局。

下面是一个简单的内置结构指令的例子:

<!-- src/app/hero-list.component.html (structural) -->

<li *ngFor="let hero of heroes"></li>
<hero-detail *ngIf="selectedHero"></hero-detail>
  1. *ngFor告诉 Angular 为heroes列表中的每个英雄生成一个<li>标签。
  2. *ngIf表示只有在选择的英雄存在时,才会包含HeroDetail组件。

b. 属性指令:修改一个现有元素的外观或行为。

简单例子:

<!-- src/app/hero-detail.component.html -->
<input [(ngModel)]="hero.name">

7. 服务 (service)

服务是一个广义范畴,包括:值、函数,或应用所需的特性。几乎任何东西都可以是一个服务。 典型的服务是一个类,具有专注的、明确的用途。它应该做一件特定的事情,并把它做好。

例如:

  1. 日志服务
  2. 数据服务
  3. 消息总线
  4. 税款计算器
  5. 应用程序配置

组件类应保持精简。组件本身不从服务器获得数据、不进行验证输入,也不直接往控制台写日志。 它们把这些任务委托给服务。所以说服务是跑腿的,服务一般用来处理业务逻辑,被注入在组件当中,服务是全局单例的。也就是说注入到所有组件中的服务是同一个。

一个简单的例子:

// src/app/hero.service.ts 

export class HeroService {
 private heroes: Hero[] = [];

 constructor(
  private backend: BackendService,
  private logger: Logger) { }

 getHeroes() {
  this.backend.getAll(Hero).then( (heroes: Hero[]) => {
   this.logger.log(`Fetched ${heroes.length} heroes.`);
   this.heroes.push(...heroes); // fill cache
  });
  return this.heroes;
 }
}

8. 依赖注入 (denpendency injection)

“依赖注入”是提供类的新实例的一种方式,还负责处理好类所需的全部依赖。大多数依赖都是服务。 Angular 使用依赖注入来提供新组件以及组件所需的服务。

来看注入方式:

// src/app/hero-list.component.ts

constructor(private service: HeroService) { }

注入器维护了一个服务实例的容器,存放着以前创建的实例。 如果所请求的服务实例不在容器中,注入器就会创建一个服务实例,并且添加到容器中,然后把这个服务返回给 Angular。 当所有请求的服务都被解析完并返回时,Angular 会以这些服务为参数去调用组件的构造函数。 这就是依赖注入 。

通常我们将服务声明在根模块,以便在整个应用中使用这个服务。

// src/app/app.module.ts

providers: [
 BackendService,
 HeroService,
 Logger
],

也可以在其他组件中声明服务,那么这个服务只能用于当前组件。把它注册在组件级表示该组件的每一个新实例都会有一个服务的新实例。

// src/app/hero-list.component.ts

@Component({
 selector:  'hero-list',
 templateUrl: './hero-list.component.html',
 providers: [ HeroService ]
})

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
IE中图片的onload事件无效问题和解决方法
Jun 06 Javascript
IE中JS跳转丢失referrer问题的2个解决方法
Jul 18 Javascript
WordPress中利用AJAX异步获取评论用户头像的方法
Jan 08 Javascript
AngularJs 60分钟入门基础教程
Apr 03 Javascript
jquery版轮播图效果和extend扩展
Jul 18 jQuery
js事件委托和事件代理案例分享
Jul 25 Javascript
[js高手之路]单例模式实现模态框的示例
Sep 01 Javascript
浅谈Vue响应式(数组变异方法)
May 07 Javascript
解决vue移动端适配问题
Dec 12 Javascript
vue + axios get下载文件功能
Sep 25 Javascript
jQuery Raty星级评分插件使用方法实例分析
Nov 25 jQuery
Vue项目开发常见问题和解决方案总结
Sep 11 Javascript
vue之数据交互实例代码
Jun 20 #Javascript
jquery加载单文件vue组件的方法
Jun 20 #jQuery
Angular.JS中select下拉框设置value的方法
Jun 20 #Javascript
原生js二级联动效果
Jun 20 #Javascript
angularjs下拉框空白的解决办法
Jun 20 #Javascript
JS使用ActiveXObject实现用户提交表单时屏蔽敏感词功能
Jun 20 #Javascript
20行js代码实现的贪吃蛇小游戏
Jun 20 #Javascript
You might like
根德YB400的电路分析
2021/03/02 无线电
thinkphp命名空间用法实例详解
2015/12/30 PHP
laravel按天、按小时,查询数据的实例
2019/10/09 PHP
PHP设计模式(六)桥连模式Bridge实例详解【结构型】
2020/05/02 PHP
ext监听事件方法[初级篇]
2008/04/27 Javascript
JS 动态加载脚本的4种方法
2009/05/05 Javascript
jQuery 常见开发使用技巧总结
2009/12/26 Javascript
javascript之typeof、instanceof操作符使用探讨
2013/05/19 Javascript
解析javascript 数组以及json元素的添加删除
2013/06/26 Javascript
js跨域问题浅析及解决方法优缺点对比
2014/11/08 Javascript
深入浅析同源策略和跨域访问
2015/11/26 Javascript
一步一步封装自己的HtmlHelper组件BootstrapHelper(二)
2016/09/14 Javascript
jQuery将表单序列化成一个Object对象的实例
2016/11/29 Javascript
Web 开发中Ajax的Session 超时处理方法
2017/01/19 Javascript
JS+HTML5 FileReader实现文件上传前本地预览功能
2020/03/27 Javascript
移动设备手势事件库Touch.js使用详解
2017/08/18 Javascript
javascript实现日历效果
2019/06/17 Javascript
jQuery开发仿QQ版音乐播放器
2020/07/10 jQuery
python中cPickle用法例子分享
2014/01/03 Python
Python脚本判断 Linux 是否运行在虚拟机上
2015/04/25 Python
tensorflow 恢复指定层与不同层指定不同学习率的方法
2018/07/26 Python
Python 一键制作微信好友图片墙的方法
2019/05/16 Python
python判断单向链表是否包括环,若包含则计算环入口的节点实例分析
2019/10/23 Python
Django中文件上传和文件访问微项目的方法
2020/04/27 Python
pycharm + django跨域无提示的解决方法
2020/12/06 Python
HTML5 Canvas画线技巧——实现绘制一个像素宽的细线
2013/08/02 HTML / CSS
localStorage的过期时间设置的方法详解
2018/11/26 HTML / CSS
给同事的道歉信
2014/01/11 职场文书
餐饮管理自我介绍信
2014/01/15 职场文书
廉政承诺书
2015/01/19 职场文书
婚礼庆典答谢词
2015/01/20 职场文书
初中班长竞选稿
2015/11/20 职场文书
2016年学校党支部创先争优活动总结
2016/04/05 职场文书
八年级地理课件资料及考点知识分享
2019/08/30 职场文书
导游词之湖北梁子湖
2019/11/07 职场文书
HTML页面中使两个div并排显示的实现
2022/05/15 HTML / CSS