第1章:Angular核心概念——模块化、依赖注入、TypeScript基础、RxJS入门

大家好,我是你们的前端老司机。今天咱们聊聊Angular。

说实话,Angular在圈子里一直是个「争议人物」。有人嫌它重,有人嫌它学习曲线陡。但我个人觉得,它其实是框架界的「瑞士军刀」——功能齐全,但得会用。

这一章,我带你拆解Angular的四个核心概念。搞懂了它们,你基本就拿到了Angular的入场券。

1.1 模块化:Angular的「乐高积木」

Angular的模块化,说白了就是「分而治之」。你想想看,一个大型应用动辄几十万行代码,全塞在一起谁受得了?

Angular用 NgModule 来组织代码。每个模块就是一个功能单元,有自己的组件、服务、指令。

核心要点:一个Angular应用至少有一个根模块(AppModule),其他功能模块按需引入。

我在项目中遇到过最典型的场景:一个电商后台,订单管理、商品管理、用户管理各占一个模块。这样团队分工明确,互不干扰。

// 一个典型的模块定义
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';

@NgModule({
  declarations: [AppComponent],   // 声明组件
  imports: [BrowserModule],       // 引入其他模块
  providers: [],                  // 注册服务
  bootstrap: [AppComponent]       // 启动组件
})
export class AppModule { }

嗯,这里要注意:declarations 只放当前模块的组件,别把别的模块的组件也塞进来。我曾经见过一个新手把所有组件都堆在一个模块里,结果编译慢得像蜗牛。

1.2 依赖注入:Angular的「后勤部长」

依赖注入(DI)是Angular最强大的特性之一。它解决了一个核心问题:对象之间的依赖关系谁来管?

你想想看,如果每个组件都自己去new一个服务,那代码耦合度得多高?改个服务构造函数,所有组件都得跟着改。

我的习惯:把可复用的逻辑(如API请求、数据缓存)都封装成服务,通过DI注入到组件中。这样组件只关心UI,服务只关心业务。

Angular的DI分三步:

  1. 提供服务:在模块或组件的 providers 里注册
  2. 注入依赖:在组件的构造函数里声明
  3. 使用服务:直接调用服务的方法
// 定义一个服务
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'  // 全局单例
})
export class DataService {
  getData() {
    return ['Angular', 'React', 'Vue'];
  }
}

// 在组件中注入
import { Component } from '@angular/core';
import { DataService } from './data.service';

@Component({
  selector: 'app-list',
  template: `<ul><li *ngFor="let item of items">{{item}}</li></ul>`
})
export class ListComponent {
  items: string[];

  constructor(private dataService: DataService) {
    this.items = this.dataService.getData();
  }
}

避坑指南:我曾经在大型项目中遇到过「循环依赖」的问题——服务A依赖服务B,服务B又依赖服务A。Angular会直接报错。解决办法是用 Injector 手动注入,或者重构代码消除循环。

1.3 TypeScript基础:Angular的「骨架」

Angular从出生就拥抱TypeScript。为什么?因为类型系统能帮你提前发现80%的运行时错误。

我个人觉得,TypeScript对Angular来说不是「可选项」,而是「必需品」。你想想看,没有类型约束,你怎么保证一个组件接收的参数一定是字符串而不是数字?

Angular中常用的TypeScript特性:

特性 说明 Angular中的典型用法
接口(Interface) 定义数据结构 定义组件输入输出的类型
装饰器(Decorator) 给类添加元数据 @Component@Injectable
泛型(Generics) 类型参数化 HttpClient的响应类型
访问修饰符 控制成员可见性 privatepublic
// 接口定义
export interface User {
  id: number;
  name: string;
  email: string;
  role: 'admin' | 'user';
}

// 组件中使用
@Component({...})
export class UserProfileComponent {
  @Input() user: User;  // 类型约束

  updateEmail(newEmail: string) {
    // 类型安全
    this.user.email = newEmail;
  }
}

小技巧:我习惯在项目根目录建一个 types 文件夹,专门放全局类型定义。这样所有模块都能复用,不用到处重复定义。

1.4 RxJS入门:Angular的「异步引擎」

RxJS是Angular处理异步操作的基石。说白了,它就是「用观察者模式处理数据流」。

你可能会问:为什么不用Promise?Promise只能处理一次异步结果,而RxJS的Observable可以处理「持续的数据流」——比如用户输入、WebSocket消息、HTTP请求的多次响应。

RxJS的核心概念就三个:

  • Observable:数据生产者,可以持续发出值
  • Observer:数据消费者,订阅Observable
  • Operators:操作符,对数据流进行变换、过滤、组合
// 一个简单的RxJS示例
import { Observable } from 'rxjs';
import { map, filter } from 'rxjs/operators';

// 创建Observable
const source$ = new Observable<number>(observer => {
  observer.next(1);
  observer.next(2);
  observer.next(3);
  observer.complete();
});

// 使用操作符处理数据流
const processed$ = source$.pipe(
  filter(x => x > 1),   // 过滤掉1
  map(x => x * 10)       // 乘以10
);

// 订阅
processed$.subscribe({
  next: value => console.log(value),  // 输出: 20, 30
  error: err => console.error(err),
  complete: () => console.log('完成')
});

Angular中的RxJS应用场景:

  • HttpClient的请求返回Observable
  • 表单控件的值变化(valueChanges)
  • 路由参数的变化(params)
  • 组件间的通信(Subject)

我记得刚开始用RxJS时,最头疼的就是「什么时候该取消订阅」。后来养成了习惯:在组件销毁时调用 unsubscribe(),或者用 async 管道让Angular自动管理。

避坑指南:我曾经在项目中遇到「内存泄漏」问题——一个组件订阅了某个Observable,但组件销毁时没取消订阅。结果这个组件被反复创建销毁,订阅越来越多,最后浏览器直接卡死。解决方案:用 takeUntil 操作符,配合一个Subject来统一管理取消订阅。

// 安全的订阅方式
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

export class MyComponent implements OnDestroy {
  private destroy$ = new Subject<void>();

  ngOnInit() {
    this.http.get('/api/data')
      .pipe(takeUntil(this.destroy$))
      .subscribe(data => {
        // 处理数据
      });
  }

  ngOnDestroy() {
    this.destroy$.next();
    this.destroy$.complete();
  }
}

好了,这一章的内容就到这里。模块化让你组织代码,依赖注入让你解耦,TypeScript让你安全,RxJS让你处理异步。这四个概念就像Angular的「四根柱子」,撑起了整个框架。

下一章,我们聊聊Angular的组件通信——父子组件、兄弟组件、跨层级组件,各种姿势都有。到时候见!


公众号:蓝海资料掘金营,微信deep3321