【angular教程240109】06 Angular父子组件以及组件之间通讯
目录:
- [【angular教程240109】06 Angular父子组件以及组件之间通讯](#【angular教程240109】06 Angular父子组件以及组件之间通讯)
-
- [一、子组件获取父组件的数据、执行子组件的方法 父组件给子组件传值-@input](#一、子组件获取父组件的数据、执行子组件的方法 父组件给子组件传值-@input)
- [二、子组件通过@Output 结合事件驱动实现组件通讯](#二、子组件通过@Output 结合事件驱动实现组件通讯)
-
- [1 子组件](#1 子组件)
- [三、 父组件发送/接受到子组件的数据、父组件执行子组件方法 (综合)](#三、 父组件发送/接受到子组件的数据、父组件执行子组件方法 (综合))
- [四、 非父子组件通讯](#四、 非父子组件通讯)
-
- [1. 服务与依赖注入(DI)](#1. 服务与依赖注入(DI))
- [2. RxJS Subjects 和 Observables](#2. RxJS Subjects 和 Observables)
- [3. NgRx](#3. NgRx)
- [4. 事件总线(Event Bus)](#4. 事件总线(Event Bus))
- [5. Local Storage 或 Session Storage](#5. Local Storage 或 Session Storage)
- [6. Query Params 或 Router State](#6. Query Params 或 Router State)
一、子组件获取父组件的数据、执行子组件的方法 父组件给子组件传值-@input
1子组件
html
<p>header works!-------------</p>
<header>{{title}}--{{msg}}</header>
<br>
<button (click)="getParentMsg()">子组件header里面获取父组件hone传入的数据msg</button>
<br>
<button (click)="getParentRun()">子组件header里面执行父组件home的run方法</button>
<p>header works!-------------</p>
ts
import { Component, OnInit, Input } from '@angular/core';
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss'],
})
export class HeaderComponent implements OnInit {
//接受父组件传来的数据
@Input() title: any;
@Input() msg: any;
//接受父组件传来的方法
@Input() run: any;
//传入整个父组件
@Input() home: any;
constructor() {}
ngOnInit() {}
//执行父组件的run 方法
// this.run();
getParentMsg() {
//获取父组件的数据
alert(this.msg);
}
getParentRun() {
//执行父组件的run 方法
// this.run();
alert(this.home.msg);
this.home.run();
}
}
二、子组件通过@Output 结合事件驱动实现组件通讯
1 子组件
html
html
<p>footer works!</p>
<button (click)="sendParent()">我是子组件footer来给父组件广播数据 </button>
ts
import { Component,OnInit,Output,EventEmitter } from '@angular/core';
// Output 和 EventEmitter 分别用于定义输出属性和创建事件发射器。
// 代码是Angular组件编程中常见的一部分,
// 用于定义一个可以发射事件给其父组件的输出属性。这是实现Angular组件间通信的一种方式。
@Component({
selector: 'app-footer',
templateUrl: './footer.component.html',
styleUrls: ['./footer.component.scss']
})
export class FooterComponent implements OnInit{
@Output() private myouter=new EventEmitter;
/*
这是一个装饰器(Decorator),用于Angular的组件(Component)中。
@Output() 表明这是一个输出属性,允许该组件向其父组件发送数据。
private outer = new EventEmitter;
创建了一个新的事件发射器(EventEmitter)实例,并将其赋值给私有属性outer。
这个事件发射器用于发射事件。
*/
ngOnInit(): void {
throw new Error('Method not implemented.');
}
sendParent(){
alert(123244);
this.myouter.emit('号外号外!!!我是一个来自子组件footer的数据')
}
}
三、 父组件发送/接受到子组件的数据、父组件执行子组件方法 (综合)
父组件
html
<hr><p>-------------home works!</p>
<app-header [title]="title" [msg]="msg" [home]="this" ></app-header>
<!--Angular组件标签。[title]、[msg]和[home]是属性绑定,它们将父组件的属性值传递给子组件。-->
<!-- <app-footer (myouter)="run()"></app-footer> -->
<app-footer (myouter)="run($event)"></app-footer>
<!--这里的run($event)会在myouter事件触发时执行,$event是事件对象。-->
<p>-------------home works!</p>
<hr>
ts
import { Component, OnInit } from '@angular/core';
// 定义一个组件,指定选择器、HTML模板和样式文件的URL
@Component({
selector: 'app-home', // 定义组件的选择器,用于在HTML中引用
templateUrl: './home.component.html', // 指定组件的HTML模板文件
styleUrls: ['./home.component.scss'], // 指定组件的样式文件
})
export class HomeComponent implements OnInit {
ngOnInit(): void {} // ngOnInit是生命周期钩子,组件初始化时调用
public title: string = '我是首页home的title'; // 定义一个公共属性title
public msg: string = '我是首页home的msg'; // 定义一个公共属性msg
// run方法,被子组件触发的事件处理函数
run(e: any) {
alert('我是父组件的run方法'); // 显示警告框
console.log(e); // 在控制台输出事件对象
}
handleChild() {} // 定义一个空方法,可能用于未来的子组件交互
}
或,上一片文章:父组件通过@ViewChild主动获取子组件的数据和方法
四、 非父子组件通讯
在Angular中,非父子组件(即兄弟组件或完全不相关的组件)之间的通信可以通过多种方式实现。这些通信方式适用于当组件没有直接的层级关系时。以下是几种常见的通信方法:
1. 服务与依赖注入(DI)
服务是Angular中一个非常强大的特性,可以用来在组件之间共享数据和行为。你可以创建一个可注入的服务来充当中介,通过它来进行组件间的通信。
typescript
@Injectable({
providedIn: 'root' // 提供在根模块中,这样整个应用都可以访问这个服务
})
export class DataService {
private data = new BehaviorSubject<any>(null);
setData(value: any) {
this.data.next(value);
}
getData(): Observable<any> {
return this.data.asObservable();
}
}
任何组件都可以注入这个服务,并使用它来发送或接收数据。
在Angular中,当使用 @Injectable 装饰器并设置 providedIn: 'root' 属性时,服务默认是以单例(Singleton)模式提供的。这意味着整个应用中只会创建该服务的一个实例,无论它被注入到多少个组件或其他服务中。
这是一个单例服务的例子:
typescript
@Injectable({
providedIn: 'root'
})
export class SingletonService {
// 这个服务的实例将在整个应用中是唯一的
}
这种单例行为确保了服务的状态和逻辑在应用 的不同部分之间保持一致。不过,Angular也允许将服务的作用域限定到特定模块或组件。如果服务在一个Angular模块或组件中的 providers 数组 里提供,那么该服务的实例将限定在该模块或组件及其子组件中。这种情况下,服务不再是单例的。
例如:
typescript
@NgModule({
providers: [NonSingletonService] // 这将为每个导入该模块的消费者创建服务的新实例
})
export class SomeModule { }
在上面的例子中,NonSingletonService 对于导入 SomeModule 的每个消费者来说都是一个新的实例。
总结来说,是否为单例取决于服务是如何提供的:
使用 providedIn: 'root' 或提供到 AppModule:服务是应用级别的单例。
提供到特定模块的 providers:每个导入该模块的消费者都会获得服务的新实例。
提供到组件的 providers:每个组件实例都会获得服务的新实例,只用于该组件及其子组件。
2. RxJS Subjects 和 Observables
RxJS是一个库,它提供了强大的数据流控制能力。Angular服务通常使用RxJS中的 Subject 或 BehaviorSubject 来创建可观察的数据流。
typescript
// 在服务中
private mySubject = new Subject<any>();
sendMessage(message: string) {
this.mySubject.next(message);
}
getMessage(): Observable<any> {
return this.mySubject.asObservable();
}
// 在发送消息的组件中
this.dataService.sendMessage('Hello from Component A!');
// 在接收消息的组件中
this.dataService.getMessage().subscribe(message => {
console.log(message); // 输出 'Hello from Component A!'
});
3. NgRx
NgRx是一个基于RxJS的框架,用于在Angular应用中管理状态和允许组件间的通信。它提供了一个全局的状态管理,通过Actions和Reducers来处理状态的更新。
4. 事件总线(Event Bus)
虽然这不是Angular推荐的做法,但在某些情况下,创建一个事件总线(Event Bus)可以作为组件间通信的手段。通常,这涉及到创建一个服务,该服务包含一个 Subject,允许发送和接收消息。
5. Local Storage 或 Session Storage
对于需要持久化数据,或者在用户导航到不同页面时保持数据的场景,你可以使用Web Storage API(如Local Storage或Session Storage)来存储数据。
6. Query Params 或 Router State
如果组件间的通信与路由导航有关,你可以使用路由的Query Params或Router State来传递数据。
选择哪种方法取决于的具体需求,例如:
如果需要一个集中式的状态管理,可能会选择NgRx。
如果希望通过订阅模式来共享数据,可能会选择使用服务和RxJS。
对于更简单的需求,可能使用Local Storage或Session Storage更为直接。
Angular的服务和RxJS通常是最常见和推荐的方法,因为它们提供了一种清晰和响应式的方式来处理应用状态和事件。