【angular教程240109】06 Angular父子组件以及组件之间通讯
目录:
一、子组件获取父组件的数据、执行子组件的方法 父组件给子组件传值-@input
1子组件
<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>
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
<p>footer works!</p>
<button (click)="sendParent()">我是子组件footer来给父组件广播数据 </button>
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的数据')
}
}
三、 父组件发送/接受到子组件的数据、父组件执行子组件方法 (综合)
父组件
<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>
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中一个非常强大的特性,可以用来在组件之间共享数据和行为。你可以创建一个可注入的服务来充当中介,通过它来进行组件间的通信。
@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)模式提供的。这意味着整个应用中只会创建该服务的一个实例,无论它被注入到多少个组件或其他服务中。
这是一个单例服务的例子:
@Injectable({
providedIn: 'root'
})
export class SingletonService {
// 这个服务的实例将在整个应用中是唯一的
}
这种单例行为确保了服务的状态和逻辑在应用的不同部分之间保持一致。不过,Angular也允许将服务的作用域限定到特定模块或组件。如果服务在一个Angular模块或组件中的 providers 数组里提供,那么该服务的实例将限定在该模块或组件及其子组件中。这种情况下,服务不再是单例的。
例如:
@NgModule({
providers: [NonSingletonService] // 这将为每个导入该模块的消费者创建服务的新实例
})
export class SomeModule { }
在上面的例子中,NonSingletonService 对于导入 SomeModule 的每个消费者来说都是一个新的实例。
总结来说,是否为单例取决于服务是如何提供的:
使用 providedIn: ‘root’ 或提供到 AppModule:服务是应用级别的单例。
提供到特定模块的 providers:每个导入该模块的消费者都会获得服务的新实例。
提供到组件的 providers:每个组件实例都会获得服务的新实例,只用于该组件及其子组件。
2. RxJS Subjects 和 Observables
RxJS是一个库,它提供了强大的数据流控制能力。Angular服务通常使用RxJS中的 Subject 或 BehaviorSubject 来创建可观察的数据流。
// 在服务中
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通常是最常见和推荐的方法,因为它们提供了一种清晰和响应式的方式来处理应用状态和事件。