详解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 相关文章推荐
javascript prototype,executing,context,closure
Dec 24 Javascript
javascript 动态加载 css 方法总结
Jul 11 Javascript
jQuery实战之仿淘宝商城左侧导航效果
Apr 12 Javascript
浏览器页面区域大小的js获取方法
Sep 21 Javascript
javascript 小数取整简单实现方式
May 30 Javascript
js流动式效果显示当前系统时间
May 16 Javascript
详解JavaScript中this关键字的用法
May 26 Javascript
最常见的左侧分类菜单栏jQuery实现代码
Nov 28 Javascript
深入浅析JavaScript中的RegExp对象
Sep 18 Javascript
手把手教你vue-cli单页到多页应用的方法
May 31 Javascript
localstorage实现带过期时间的缓存功能
Jun 28 Javascript
antdesign-vue结合sortablejs实现两个table相互拖拽排序功能
Jan 08 Vue.js
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
php面向对象全攻略 (二) 实例化对象 使用对象成员
2009/09/30 PHP
php strstr查找字符串中是否包含某些字符的查找函数
2010/06/03 PHP
PHP使用curl制作简易百度搜索
2016/11/03 PHP
js脚本学习 比较实用的基础
2006/09/07 Javascript
JS之小练习代码
2008/10/12 Javascript
javascript克隆对象深度介绍
2012/11/20 Javascript
javascript+xml实现简单图片轮换(只支持IE)
2012/12/23 Javascript
JS实现标签页效果(配合css)
2013/04/03 Javascript
在JavaScript中typeof的用途介绍
2013/04/11 Javascript
JS弹出层的显示与隐藏示例代码
2013/12/27 Javascript
DOM基础教程之使用DOM控制表格
2015/01/20 Javascript
javascript实现日期时间动态显示示例代码
2015/09/08 Javascript
js判断某个字符出现的次数的简单实例
2016/06/03 Javascript
mvvm双向绑定机制的原理和实现代码(推荐)
2016/06/07 Javascript
基于js对象,操作属性、方法详解
2016/08/11 Javascript
RequireJS简易绘图程序开发
2016/10/28 Javascript
在js代码拼接dom对象到页面上去的模板总结(必看)
2017/02/14 Javascript
vue-router单页面路由
2017/06/17 Javascript
详解Vue webapp项目通过HBulider打包原生APP
2018/06/29 Javascript
如何使用 vue + d3 画一棵树
2018/12/03 Javascript
vue.js路由mode配置之去掉url上默认的#方法
2019/11/01 Javascript
Vue实现图书管理小案例
2020/12/03 Vue.js
[43:58]DOTA2-DPC中国联赛定级赛 LBZS vs SAG BO3第一场 1月8日
2021/03/11 DOTA
Python判断Abundant Number的方法
2015/06/15 Python
Python环境变量设置方法
2016/08/28 Python
python 与GO中操作slice,list的方式实例代码
2017/03/20 Python
一个基于flask的web应用诞生 bootstrap框架美化(3)
2017/04/11 Python
Python中实例化class的执行顺序示例详解
2018/10/14 Python
两个元祖T1=('a', 'b'),T2=('c', 'd')使用匿名函数将其转变成[{'a': 'c'},{'b': 'd'}]的几种方法
2019/03/05 Python
python属于解释语言吗
2020/06/11 Python
HTML5 CSS3新的WEB标准和浏览器支持
2009/07/16 HTML / CSS
KLOOK客路:发现更好玩的世界,预订独一无二的旅行体验
2016/12/16 全球购物
美国电子产品折扣网站:Daily Steals
2017/05/20 全球购物
不同浏览器创建XMLHttpRequest方法有什么不同
2014/11/17 面试题
领导检查欢迎词
2014/01/14 职场文书
项目转让协议书
2014/10/27 职场文书