Skip to content

Angular必知八大概念 #48

Open
@deepthan

Description

@deepthan

Angular必知八大概念

  • 模块
    模块有两层含义:

    1. 框架代码以模块形式组织(物理模块)
    2. 功能单元以模块形式组织(逻辑模块)
      物理模块是TS/ES6提供的文件模块特征
      逻辑模块是对应应用内零散的组件、指令、服务按功能进行分类包装,其关系示意图如下:
      image

    首先,Angular 要能成功运行,至少需要定义一个模块,因为需要有一个模块作为应用启动的入口,这样的模块就称为根模块。
    然后,我们的应用会不断的添加新的功能。这些新增的功能可以封装到一个新的模块里。这些新增加的模块在 angular 里称为特性模块。有了特性模块之后,根模块原来承载在功能逻辑也可以抽离出来,放到某个特性模块里,使根模块保持简洁。
    接下来,我们添加的特性模块越来越多,他们之间可以抽出一些相似功能的组件或指令,这些公共的部分也可以封装成一个独立的模块,这样的模块在逻辑意义上不能称为特性模块,Angular 把他称为为共享模块。
    最后,还有核心模块,我们知道,一个应用里总有一些全局的组件或服务等,他们只需要在应用启动时候初始化一次即可,例如,维护登录信息的服务,或者是,公共的头部和尾部组件等。虽然我们可以把他们放到根模块里,但更好的设计是把这些逻辑也抽离出来,放到一个独立的模块,这个模块即为核心模块。核心模块要求只导入到根模块里,而尽量不要导入到特性模块或者共享模块里,这是为了在协同工作时候避免出现一些不可预料的结果。

    Angular 已经封装了不少常用的模块, 如:

    ApplicationModule:封装一些启动相关的工具;
    CommonModule:封装一些常用的内置指令和内置管道等;
    BrowserModule:封装在浏览器平台运行时的一些工具库,同时将 CommonModule 和 ApplicationModule 打包导出,所以通常在使用时引入 BrowserModule 就可以了;
    FormsModule 和 ReactiveFormsModule:封装表单相关的组件指令等;
    RouterModule:封装路由相关的组件指令等;
    HttpModule:封装网络请求相关的服务等。

    所以,如果你想使用 ngIf 和 ngStyle 等这些内置指令,记得先导入 CommonModule,其他的模块使用方法一致。

  • 组件

    组件由两部分组成的: @component和 类。
    image
    如果只是定义一个类,angular不知道怎么解释这个类,当往这个类里注入组件元数据后,angular才知道把这个类解释为组件。

    如果想了解元数据是如何注入到类里,可深入了解 reflect-metadata 这个 polyfill。

    数据绑定适用于层级相隔不远的组件,层级太深或者不同分支的组件通讯通常采用其他方式,例如利用服务作为中介。

  • 模板
    angular模板基于HTML,普通的html亦可作为模板输入。

@Component({
  template: `<p>deepthan</p>`
})
  • 元数据
    @component是装饰器,元数据主要以装饰器的函数参数指定。
    selector和 template都是元数据。
    装饰器实际上是一个自定义函数,angular的各种装饰器处理函数在modules/@angular/core/src/util/decorators.ts 中。

  • 数据绑定
    属性绑定和数据绑定均称为数据绑定。

    1. 插值
    <p>你好,{{data.name}}</p>
    
    1. 属性绑定
    [deep] = 'data[0]'
    
    1. 事件绑定
    (sendData) = getData(value) 
    
    1. 双向绑定
    <input [(ngModel)='value']>
    

    [()]是实现双向绑定的语法糖,ngmodel是辅助实现双向绑定的内置指令。 input框和value之间形成数据关联, input值发生变更时会自动赋值到 value,而value值被组件类改变时也可更新input的值。

  • 指令
    指令可以通过与dom进行灵活交互,改变样式或改变布局。

    1. 结构指令: 增加、删除、修改DOM,如 ngIf、 ngFor
    <p *ngIf='bol==true'></p>
    
    1. 属性指令 : 改变元素的外观或者行为,如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 }
    ]
  }
]
  1. 子路由下面有个特性模块,懒加载:
const routes: Route: [
  { 
    path: 'role', 
    children: [
      { path: "login", () => import('./login/login.module').then((m) => m.LoginModule)}
    ]
  }
]

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions