Skip to content
 

Angular 组件 相关

更新: 8/13/2026字数: 0 字 时长: 0 分钟

一 、组件的基本构成

Angular 组件的基本构成:

js
import { Component } from "@angular/core";
import { RouterOutlet } from "@angular/router";

// @Component 是ts的装饰器  修饰class AppComponent类的
@Component({
  selector: "app-root", // 组件的标签名
  imports: [RouterOutlet], // 引入组件
  templateUrl: "./app.component.html", // 引入模板
  styleUrl: "./app.component.scss" // 引入样式 单独的样式文件
})
export class AppComponent {
  title = "my-app";
  obj = { name: "xinjie", age: 18 };
}

注意:所有的装饰器本质上都是一个函数,所以要加小括号()

创建组件的简化命令:

 ng generate component 组件名 // 可以快速创建组件;其中generate还可以简化为 g;

ng 命令式安装 angular 脚手架时安装的 可执行命令;在 node_modules 里面的 bin 文件夹里面

扩展知识:

node.js 官方安装的工具:

  1. npm : 第三方模块的维护工具
  2. npx :第三方可执行文件的执行工具;node package executor;npx 可执行当前项目中 node_modules/bin/ 目录下面的可执行文件(后缀为 cmd)

二 、组件引入

Angular 支持两种方式将组件提供给其他组件:作为独立的组件或在 NgModule中。

2.1、独立组件方式

ts
@Component({
  standalone: true, // 声明为独立组件
  selector: "profile-photo"
})
export class ProfilePhoto {}

@Component({
  standalone: true,
  imports: [ProfilePhoto], // 在另一个组件中引入 即可使用
  template: `<profile-photo />`
})
export class UserProfile {}

2.2、NgModules 方式

在 Angular 中,每个模块的 .module.ts 文件是模块的核心配置文件,用于定义和组织模块的功能、组件、服务、指令等。它通过 @NgModule 装饰器来配置模块的行为和结构。

NgModule 是一个由 @NgModule 装饰器标记的类。 @NgModule 接受一个描述如何编译组件模板以及如何在运行时创建注入器的元数据对象。 它标识模块自身的组件、指令和管道,并通过 exports 属性使其中一些公开,以便外部组件可以使用它们。

welcome.module.ts 文件如下:

ts
import { NgModule } from "@angular/core";

import { WelcomeRoutingModule } from "./welcome-routing.module";

import { FormsModule } from "@angular/forms";
import { WelcomeComponent } from "./welcome.component";
import { NzRateModule } from "ng-zorro-antd/rate";

// 装饰器
@NgModule({
  declarations: [WelcomeComponent], // 声明组件、指令和管道
  exports: [WelcomeComponent], // 导出模块中的资源
  imports: [BrowserModule], // 导入其他模块
  bootstrap: [AppComponent], // 指定根组件
  providers: [] // 提供服务
})
export class WelcomeModule {}
import { NgModule } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";
import { AppComponent } from "./app.component";

总结

.module.ts 文件是 Angular 模块的核心配置文件,其主要作用包括:

  1. 定义模块的元数据。
  2. 声明模块中的组件、指令和管道。
  3. 导入其他模块。
  4. 提供服务。
  5. 指定根组件。
  6. 导出资源。
  7. 定义模块的作用域。

通过 .module.ts 文件,Angular 可以清晰地组织和管理模块的资源,实现模块化开发。

三 、组件的生命周期

阶段描述备注
constructor在 Angular 实例化组件时运行。
ngOnChanges每次组件输入发生变化时运行。(组件绑定的属性值发生变化)在初始化期间,第一个 ngOnChanges 会在 ngOnInit 之前运行。
ngOnInit组件初始化完成。必须掌握。等同于 vue 的 mounted。
ngDoCheck每次检查此组件是否有变化时运行。
ngAfterViewInit在组件的 视图 初始化后运行一次。
ngAfterContentInit在组件的 内容 初始化后运行一次。
ngAfterViewChecked每次检查组件视图是否有变化时运行。
ngAfterContentChecked每次检查此组件内容是否有变化时运行。
afterNextRender所有组件都已渲染到 DOM 时运行一次。
afterRender每次所有组件都渲染到 DOM 时运行。
ngOnDestroy销毁,在组件被销毁前运行一次。必须掌握。

生命周期总体:分为 创建(constructor),检测,渲染(afterNextRender 和 afterRender),销毁 (ngOnDestroy)四个大的阶段;

四 、组件传值

4.1 父传子

同样是使用自定义属性,但是子组件需要@input 这个输入属性装饰器来接收属性

html
<h2>这是 {{userName}}的博客</h2>
<!-- 使用第一个子组件 -->
<app-first></app-first>
<!-- 使用第二个子组件 -->
<app-second childName="{{userName}}"></app-second>

子组件:

ts
import { Component, Input } from "@angular/core";
@Component({
  selector: "app-second",
  imports: [],
  templateUrl: "./second.component.html",
  styleUrl: "./second.component.scss",
  standalone: true
})
export class SecondComponent {
  // 输入属性进行接收
  @Input()
  childName: string = "未传值"; // 那么这个值就可以用到模版上面了
}

4.2 子传父

同样使用 emit 发射自定义事件,但是有些区别。

子组件:

ts
import { Component, Pipe, Output, EventEmitter } from "@angular/core";

export class FirstComponent {
  inputName = "dd";
  // 父传子
  @Output()
  cryEmit = new EventEmitter();
  updateUserName() {
    this.cryEmit.emit(this.inputName);
  }
}

父组件:

// $event用于接收参数
<app-first (cryEmit) = "cryEmit($event)"></app-first>
ts
  // 父组件接收数据
  cryEmit(params:any){
    console.log(params);
    this.userName = params;
  }

4.3 兄弟之间传值

兄弟组件之间没有直接的父子关系,无法直接通过 @Input/@Output 通信,通常有两种主流方案:

4.3.1 方式一:共享服务 + Subject(推荐)

通过一个共享服务,配合 RxJSSubject/BehaviorSubject 作为「消息总线」,实现任意组件之间的通信:

typescript
// shared.service.ts
import { Injectable } from "@angular/core";
import { Subject } from "rxjs";

@Injectable({ providedIn: "root" })
export class SharedService {
  // 消息发送器(不保存最新值,仅作为事件总线)
  private messageSource = new Subject<string>();
  // 对外暴露为 Observable,防止外部直接调用 next
  message$ = this.messageSource.asObservable();

  sendMessage(msg: string) {
    this.messageSource.next(msg);
  }
}

发送方组件(兄弟 A):

typescript
import { Component } from "@angular/core";
import { SharedService } from "./shared.service";

@Component({
  selector: "app-sibling-a",
  standalone: true,
  template: `<button (click)="send()">发送消息给兄弟</button>`
})
export class SiblingAComponent {
  constructor(private shared: SharedService) {}

  send() {
    this.shared.sendMessage("来自兄弟A的问候");
  }
}

接收方组件(兄弟 B):

typescript
import { Component, OnDestroy } from "@angular/core";
import { Subscription } from "rxjs";
import { SharedService } from "./shared.service";

@Component({
  selector: "app-sibling-b",
  standalone: true,
  template: `<p>收到的消息:{{ message }}</p>`
})
export class SiblingBComponent implements OnDestroy {
  message = "";
  private sub!: Subscription;

  constructor(private shared: SharedService) {
    this.sub = this.shared.message$.subscribe((msg) => (this.message = msg));
  }

  // 组件销毁时取消订阅,避免内存泄漏
  ngOnDestroy() {
    this.sub.unsubscribe();
  }
}

注意:使用 Subject 时,如果接收方订阅晚于发送方发送,会错过消息。若需要「总是能拿到最新值」,应改用 BehaviorSubject,并给它一个初始值。

4.3.2 方式二:通过共同的父组件「中转」

如果两个兄弟组件有共同的父组件,可以让父组件作为中介:

  1. 兄弟 A 通过 @Output 把数据 emit 给父组件;
  2. 父组件接收后,再通过 @Input 传递给兄弟 B。
html
<!-- 父组件模板 -->
<app-sibling-a (dataChange)="onDataChange($event)"></app-sibling-a>
<app-sibling-b [data]="sharedData"></app-sibling-b>
typescript
// 父组件
export class ParentComponent {
  sharedData = "";

  onDataChange(data: string) {
    this.sharedData = data; // 中转数据
  }
}

对比总结

方式优点缺点适用场景
共享服务 + Subject解耦、灵活、任意组件可通信需要手动管理订阅的生命周期跨层级、无直接关系的组件
父组件中转简单直观、数据流清晰组件层级深时逐层传递较繁琐相邻兄弟、层级简单的场景