使用服务跨组件通信

发布日期:2026-07-11 12:02:05   来源 : 杭州电子商务研究院    浏览量 :19
杭州电子商务研究院 发布日期:2026-07-11 12:02:05  
19

介绍

在任何 Angular 应用中,组件都是基本构建块。Angular 组件为我们提供应用的视图/模板。它们还管理绑定到这些视图的数据。以下是任何应用中最常见的一些数据共享场景,其中两个或多个组件在它们之间共享信息:

  1. 父组件到子组件:使用@Input装饰器(属性绑定)
  2. 子组件到父组件:使用@Output 装饰器和 EventEmitter(事件绑定)
  3. 兄弟或不相关的组件之间:使用 Angular 共享服务

让我们通过示例来看一下每个场景。

我们的示例设置

在我们的示例中,我们将向用户显示课程列表,并且在选择任何课程后,用户将看到该课程的详细信息。

下面是我们的 app.module.ts 的样子:

      //app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { AppComponent } from './app.component';
import { CourseListComponent } from './courses/course-list/course-list.component';
import { CourseItemComponent } from './courses/course-list/course-item/course-item.component';

@NgModule({
  declarations: [
    AppComponent,
    CourseListComponent,
    CourseItemComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
    

我们的课程模型如下:

      //course.model.ts
export class Course {
  public name: string;
  public description: string;
  public courseImagePath: string;

  constructor(name: string, desc: string, courseImagePath: string) {
    this.name = name;
    this.description = desc;
    this.courseImagePath = imagePath;
  }
}
    

我们的根组件或应用程序组件包含课程列表组件,如下所示:

      import { Component, OnInit } from '@angular/core';
import { Course } from './course.model';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  selectedCourse: Course;
  constructor() { }
  ngOnInit() {
  }
}
    

以下是应用程序组件的 HTML 代码:

      <div class="row">
  <div class="col-md-5">
<app-course-list
  (courseWasSelected)="selectedCourse = $event"></app-course-list>
  </div>
  <div class="col-md-7">
<app-course-detail
  *ngIf="selectedCourse; else infoText"
  [course]="selectedCourse"></app-course-detail>
<ng-template #infoText>
  <p>Please select any course to view details!</p>
</ng-template>
  </div>
</div>
    

此外,我们的课程列表组件如下所示:

      import { Component, OnInit, EventEmitter, Output } from '@angular/core';
import { Course } from '../course.model';

@Component({
  selector: 'app-course-list',
  templateUrl: './course-list.component.html',
  styleUrls: ['./course-list.component.css']
})
export class CourseListComponent implements OnInit {
  courses: Course[] = [
    new Course('Angular Course 1', 'This is simply a practice Angular course 1', 'http://via.digital.com/350x150.jpeg'),
    new Course('Angular Course 2', 'This is simply a practice Angular course 2', 'http://via.digital.com/350x150'),
	new Course('Angular Course 3', 'This is simply a practice Angular course 3', 'http://via.digital.com/350x150')
  ];

  constructor() { }

  ngOnInit() {
  }
}
    

以下是模板:

      <div class="row">
  <div class="col-xs-12">
    <button class="btn btn-success">New Course</button>
  </div>
</div>
<hr>
<div class="row">
  <div class="col-xs-12">
    <app-course-item></app-course-item>
  </div>
</div>
    

以下是我们的课程项目组成部分:

      import { Component, OnInit, Input, EventEmitter, Output } from '@angular/core';

import { Course } from '../../course.model';

@Component({
  selector: 'app-course-item',
  templateUrl: './course-item.component.html',
  styleUrls: ['./course-item.component.css']
})
export class CourseItemComponent implements OnInit {  
  constructor() { }
  ngOnInit() {  }
}
    

课程项目模板:

      <a
  href="#"
  class="list-group-item clearfix">
  <div class="pull-left"><!--Display Course Name/Desc here --></div>
  <span class="pull-right"><!--Display Course Image here--></span>
</a>
    

通过上述设置,让我们看看这些组件之间通信的不同方式。

使用 @Input 装饰器(属性绑定)

这是最常见的数据共享方式。它使用 @Input() 装饰器通过模板传递数据。@Input 装饰器允许父组件将其属性绑定到子组件,从而使子组件可以访问其数据。这些绑定实际上是对父组件属性的引用。

假设我们想将“课程”信息从 CourseListComponent 传递到 CourseItemComponent。

以下是我们如何更新课程列表模板:

      <div class="row">
  <div class="col-xs-12">
    <app-course-item
      *ngFor="let courseEl of courses"
      [course]="courseEl"></app-course-item>
  </div>
</div>
    

您可以看到,当我们遍历课程列表时,我们将该遍历的单个课程元素传递给 CourseItemComponent。因此,我们将父 CourseListComponent 中的子 CourseItemComponent 的“course”属性绑定起来。

现在,为了做到这一点,我们必须在子 CourseItemComponent 上使用 @Input 装饰器。因此,我们更新后的 CourseItemComponent 将如下所示:

      import { Component, OnInit, Input, EventEmitter, Output } from '@angular/core';

import { Course } from '../../course.model';

@Component({
  selector: 'app-course-item',
  templateUrl: './course-item.component.html',
  styleUrls: ['./course-item.component.css']
})
export class CourseItemComponent implements OnInit {
@Input() course: Course;  
  constructor() { }
  ngOnInit() {  }
}
    

我们现在可以在 CourseItemComponent 模板中呈现课程名称/描述/图像,如下所示:

      <a
  href="#"
  class="list-group-item clearfix">
  <div class="pull-left">
    <h4 class="list-group-item-heading">{{ course.name }}</h4>
    <p class="list-group-item-text">{{ course.description }}</p>
  </div>
  <span class="pull-right">
        <img
          [src]="course.courseImagePath"
          alt="{{ course.name }}"
          class="img-responsive"
          style="max-height: 50px;">
      </span>
</a>
    

使用 @Output 装饰器和 EventEmitter (事件绑定)

在某些情况下,我们希望能够将数据从子组件发射回父组件。子组件公开了一个 EventEmitter 属性,每当子组件上发生任何操作/事件时,该属性都会发射数据。

在我们上面看到的相同例子中,假设每当点击任何单个课程的链接时,我们都希望通知父组件。

因此,我们将在 CourseItemComponent 上添加一个“点击”事件。该模板的更新方式如下:

      <a
  href="#"
  class="list-group-item clearfix"
	(click)="onSelected()">
  <div class="pull-left">
    <h4 class="list-group-item-heading">{{ course.name }}</h4>
    <p class="list-group-item-text">{{ course.description }}</p>
  </div>
  <span class="pull-right">
        <img
          [src]="course.courseImagePath"
          alt="{{ course.name }}"
          class="img-responsive"
          style="max-height: 50px;">
      </span>
</a>
    

现在,从 CourseItemComponent 类型脚本代码中,我们希望能够发出此事件并将该事件通知父组件。如果我们希望“courseSelected”可从外部监听,则必须使用 @Output 装饰器。这将允许访问此属性上的 emit() 方法。此外,在创建 EventEmitter 实例时,我们可以选择定义可能发出的任何事件数据。

      import { Component, OnInit, Input, EventEmitter, Output } from '@angular/core';

import { Course } from '../../course.model';

@Component({
  selector: 'app-course-item',
  templateUrl: './course-item.component.html',
  styleUrls: ['./course-item.component.css']
})
export class CourseItemComponent implements OnInit {
@Input() course: Course;  
@Output() courseSelected = new EventEmitter<Course>();
  constructor() { }
  ngOnInit() {  }
onSelected() {
    this.courseSelected.emit(this.course);
  }
}
    

通过上述更改,我们现在可以监听父 CourseListComponent 上的“courseSelected”事件,如下所示。

      <div class="row">
  <div class="col-xs-12">
    <button class="btn btn-success">New Course</button>
  </div>
</div>
<hr>
<div class="row">
  <div class="col-xs-12">
    <app-course-item
      *ngFor="let courseEl of courses"
      [course]="courseEl"
      (courseSelected)="onCourseSelected(courseEl)"></app-course-item>
  </div>
</div>
    

此外,我们现在可以访问 CourseListComponent 打字稿代码中的“课程”。

      import { Component, OnInit, EventEmitter, Output } from '@angular/core';
import { Course } from '../course.model';

@Component({
  selector: 'app-course-list',
  templateUrl: './course-list.component.html',
  styleUrls: ['./course-list.component.css']
})
export class CourseListComponent implements OnInit {
  courses: Course[] = [
    new Course('Angular Course 1', 'This is simply a practice Angular course 1', 'http://via.digital.com/350x150.jpeg'),
    new Course('Angular Course 2', 'This is simply a practice Angular course 2', 'http://via.digital.com/350x150')
  ];

  constructor() { }

  ngOnInit(<span cl
以上内容来自杭州电子商务研究院推送
关注
关于我们
热门推荐
合作伙伴
免责声明:本站部分资讯来源于网络,如有侵权请及时联系客服,我们将尽快处理
Copyright © 2025-2027 ToB产业网址导航 公安备案 浙公网安备33010602013138号 浙ICP备16025413号-9
支持 反馈 关注 数据