Description
Angular必知八大概念
-
模块
模块有两层含义:首先,Angular 要能成功运行,至少需要定义一个模块,因为需要有一个模块作为应用启动的入口,这样的模块就称为根模块。
然后,我们的应用会不断的添加新的功能。这些新增的功能可以封装到一个新的模块里。这些新增加的模块在 angular 里称为特性模块。有了特性模块之后,根模块原来承载在功能逻辑也可以抽离出来,放到某个特性模块里,使根模块保持简洁。
接下来,我们添加的特性模块越来越多,他们之间可以抽出一些相似功能的组件或指令,这些公共的部分也可以封装成一个独立的模块,这样的模块在逻辑意义上不能称为特性模块,Angular 把他称为为共享模块。
最后,还有核心模块,我们知道,一个应用里总有一些全局的组件或服务等,他们只需要在应用启动时候初始化一次即可,例如,维护登录信息的服务,或者是,公共的头部和尾部组件等。虽然我们可以把他们放到根模块里,但更好的设计是把这些逻辑也抽离出来,放到一个独立的模块,这个模块即为核心模块。核心模块要求只导入到根模块里,而尽量不要导入到特性模块或者共享模块里,这是为了在协同工作时候避免出现一些不可预料的结果。Angular 已经封装了不少常用的模块, 如:
ApplicationModule:封装一些启动相关的工具;
CommonModule:封装一些常用的内置指令和内置管道等;
BrowserModule:封装在浏览器平台运行时的一些工具库,同时将 CommonModule 和 ApplicationModule 打包导出,所以通常在使用时引入 BrowserModule 就可以了;
FormsModule 和 ReactiveFormsModule:封装表单相关的组件指令等;
RouterModule:封装路由相关的组件指令等;
HttpModule:封装网络请求相关的服务等。所以,如果你想使用 ngIf 和 ngStyle 等这些内置指令,记得先导入 CommonModule,其他的模块使用方法一致。
-
组件
组件由两部分组成的: @component和 类。
如果只是定义一个类,angular不知道怎么解释这个类,当往这个类里注入组件元数据后,angular才知道把这个类解释为组件。如果想了解元数据是如何注入到类里,可深入了解 reflect-metadata 这个 polyfill。
数据绑定适用于层级相隔不远的组件,层级太深或者不同分支的组件通讯通常采用其他方式,例如利用服务作为中介。
-
模板
angular模板基于HTML,普通的html亦可作为模板输入。
@Component({
template: `<p>deepthan</p>`
})
-
元数据
@component是装饰器,元数据主要以装饰器的函数参数指定。
selector和 template都是元数据。
装饰器实际上是一个自定义函数,angular的各种装饰器处理函数在modules/@angular/core/src/util/decorators.ts 中。 -
数据绑定
属性绑定和数据绑定均称为数据绑定。- 插值
<p>你好,{{data.name}}</p>
- 属性绑定
[deep] = 'data[0]'
- 事件绑定
(sendData) = getData(value)
- 双向绑定
<input [(ngModel)='value']>
[()]是实现双向绑定的语法糖,ngmodel是辅助实现双向绑定的内置指令。 input框和value之间形成数据关联, input值发生变更时会自动赋值到 value,而value值被组件类改变时也可更新input的值。
-
指令
指令可以通过与dom进行灵活交互,改变样式或改变布局。- 结构指令: 增加、删除、修改DOM,如 ngIf、 ngFor
<p *ngIf='bol==true'></p>
- 属性指令 : 改变元素的外观或者行为,如ngStyle 、 ngClass
html: <p> [ngStyle]='setStyles()' </p> ts: setStyles(){ return { 'color' : 'red' } }
-
服务
服务是封装单一功能的单元,类似于工具库,常被引用于组件内部,作为组件的功能拓展。它可以是一个简单的字符串或json数据,也可以是一个函数甚至是一个类,几乎所有的对象都可以封装成服务。
一个简单的日志服务:// import statement @Injectable() export class LoggerService { private level: string; setLevel(level: string) { this.level = level; } debug(msg: string) { } warn(msg: string) { } error(msg: string) { } }
-
依赖注入
通过依赖注入机制,服务等模块可以被引入到任何一个组件(或模块或服务)中,而开发者无须关系这些模块是如何被初始化的。
可以说依赖注入是一种帮助开发者管理模块依赖的设计模式。
一个依赖注入例子:import {LoggerService} from './logger-service'; // other import statement @Component({ selector: 'contact', template: '...' providers: [LoggerService] }) export class ContactListComponent { constructor(logger: LoggerService) { logger.debug('xxx'); } }
@component 装饰器中的 providers元元数据是依赖注入操作的关键,它会为该组件创建一个注入器对象,并新建 LoggerService实例存储到这个注入器里。组件需要引入 LoggerService实例时,只需要在构造函数声明 LoggerService类型的参数即可,Angular自动地通过类型匹配,找出注入器里预先实例化好的 loggerService对象,在组件实例化时作为参数传入,这样组件便获得了 LoggerService的实例引用。
-
其他概念:
Angular 是以适当的时机去检验对象的值是否被改动,这个适当的时机并不是以固定某个频率去执行,而通常是在用户操作事件(如点击),setTimeout 或 XHR 回调等这些异步事件触发之后。Angular 捕获这些异步事件的工作是通过 Zones 库实现的.
import { LoginModule } from './login/login.module'
const routes: Route: [
{
path: 'role',
children: [
{ path: "login", loadChildren: () => LoginModule }
]
}
]
- 子路由下面有个特性模块,懒加载:
const routes: Route: [
{
path: 'role',
children: [
{ path: "login", () => import('./login/login.module').then((m) => m.LoginModule)}
]
}
]