与善为伍 發表於 2023-3-2 16:02:00

玩转Angular系列:组件间各种通信方式详解

<h2 id="前言">前言</h2>
<p>在前端框架Angular中,组件之间的通信很基础也很重要,不同组件间的通信方式也不同,掌握组件间的通信方式会更加深刻的理解和使用Angular框架。</p>
<p><img src="https://echeverra.cn/wp-content/static/article-img/angularComponentCommunication/cover1.png" alt="" loading="lazy"></p>
<p>本文讲解不同类型组件间的不同通信方式,文中所有示例均提供源码,您可以 <strong>在线编辑预览</strong> 或 <strong>下载本地调试</strong>,相信通过本文您一定可以掌握组件通信这一知识点。</p>
<h2 id="父组件传子组件">父组件传子组件</h2>
<h3 id="input方式">@Input方式</h3>
<p><img src="https://echeverra.cn/wp-content/static/article-img/angularComponentCommunication/1677226738911.jpg" alt="" loading="lazy"></p>
<p><code>@Input()</code>装饰器允许父组件更新子组件中的数据,分为4步:</p>
<p>第一步:在父组件<code>app.component.ts</code>中定义要传递给子组件的数据<code>parentMsg</code>。</p>
<pre><code>export class AppComponent {
parentMsg: string = 'parent component message!';
}
</code></pre>
<p>第二步:在父组件<code>app.component.html</code>中的子组件标签<code>&lt;app-child&gt;</code>中定义属性<code></code>(子组件接收数据变量)来绑定父组件的数据<code>parentMsg</code>。</p>
<pre><code>&lt;app-child ="parentMsg"&gt;&lt;/app-child&gt;
</code></pre>
<p>第三步:在子组件<code>child.component.ts</code>中引入<code>@Input()</code>装饰器,修饰<code>childMsg</code>接收父组件的传值。</p>
<pre><code>import { Input } from '@angular/core';

export class ChildComponent {
@Input() childMsg: string = '';
}
</code></pre>
<p>第四步:在子组件<code>child.component.html</code>中通过模板标签<code>{{childMsg}}</code>展示数据。</p>
<pre><code>&lt;div&gt;父组件传值内容:{{ childMsg }}&lt;/div&gt;
</code></pre>
<p>最终展示效果如下,您可以通过 <strong>在线示例</strong> 预览效果和编辑调试:</p>
<p><img src="https://echeverra.cn/wp-content/static/article-img/angularComponentCommunication/1677662596979.jpg" alt="" loading="lazy"></p>
<p><strong>说明</strong>:这里要理解父组件html中通过<code>[]</code>定义了一个子组件的属性,该值必须与子组件中所定义的变量名一致,而等号右边的值为父组件要传递的属性名,示例中是将父组件中<code>parentMsg</code>的值绑定在子组件<code>childMsg</code>属性上。</p>
<h2 id="子组件传父组件">子组件传父组件</h2>
<h3 id="output方式">@Output()方式</h3>
<p><img src="https://echeverra.cn/wp-content/static/article-img/angularComponentCommunication/1677226815097.jpg" alt="" loading="lazy"></p>
<p><code>@Output()</code>装饰器允许数据从子组件传给父组件,分为6步:</p>
<p>第一步:在子组件<code>child.component.ts</code>中引入<code>Output</code>和<code>EventEmitter</code>,通过<code>@Output()</code>来修饰一个<code>EventEmitter</code>实例的变量<code>newItemEvent</code>。</p>
<pre><code>import { Component, Output, EventEmitter } from '@angular/core';

export class ChildComponent {
@Output() newItemEvent = new EventEmitter&lt;string&gt;();
}
</code></pre>
<p>第二步:在子组件<code>child.component.html</code>中添加点击事件,获取输入内容,点击按钮触发<code>addNewItem()</code>方法。</p>
<pre><code>&lt;label&gt;输入项目名:&lt;input type="text" #newItem /&gt;&lt;/label&gt;
&lt;button type="button" (click)="addNewItem(newItem.value)"&gt;
添加项目到父组件
&lt;/button&gt;
</code></pre>
<p>第三步:在子组件<code>child.component.ts</code>中通过<code>newItemEvent</code>的<code>emit()</code>方法,把数据发送到父组件。</p>
<pre><code>export class ChildComponent {
@Output() newItemEvent = new EventEmitter&lt;string&gt;();

addNewItem(value: string) {
    this.newItemEvent.emit(value);
}
}
</code></pre>
<p>第四步:在父组件<code>app.component.html</code>中子组件标签<code>&lt;app-child&gt;</code>中添加父组件方法<code>addItem($event)</code>绑定到子组件的<code>newItemEvent</code>发射器事件上,其中<code>$event</code>为子组件的传递的值。</p>
<pre><code>&lt;app-child (newItemEvent)="addItem($event)"&gt;&lt;/app-child&gt;
</code></pre>
<p>第五步:在父组件<code>app.component.ts</code>中通过<code>addItem($event)</code>方法获取处理数据。</p>
<pre><code>export class AppComponent implements AfterViewInit {
items = ['item1', 'item2', 'item3'];

addItem(newItem: string) {
    this.items.push(newItem);
}
}
</code></pre>
<p>第六步:在父组件<code>app.component.html</code>中遍历<code>items</code>展示数据。</p>
<pre><code>&lt;ul&gt;
&lt;li *ngFor="let item of items"&gt;{{ item }}&lt;/li&gt;
&lt;/ul&gt;
</code></pre>
<p>最终展示效果如下,您可以通过 <strong>在线示例</strong> 预览效果和编辑调试:</p>
<p><img src="https://echeverra.cn/wp-content/static/article-img/angularComponentCommunication/90613.gif" alt="" loading="lazy"></p>
<p><strong>说明</strong>:这里要理解关键的第四步事件连接<code>(newItemEvent)="addItem($event)"</code>含义,左侧是父组件监听子组件创建的一个发射器<code>newItemEvent</code>,右侧是父组件的<code>addItem($event)</code>方法。子组件通过发射器的<code>emit(value)</code>方法广播传递值到父组件,父组件通过<code>addItem($event)</code>中的<code>$event</code>接收传值,完成通信。</p>
<h3 id="本地变量方式">本地变量方式</h3>
<p>在父组件模板里,新建一个本地变量来代表子组件,可以利用这个变量来读取子组件的属性和调用子组件的方法。分为2步:</p>
<p>第一步:在子组件<code>child.component.ts</code>中定义<code>count</code>变量和<code>addOne()</code>方法。</p>
<pre><code>export class ChildComponent {
count: number = 0;
addOne() {
    this.count++;
}
}
</code></pre>
<p>第二步:在父组件<code>app.component.html</code>中子组件标签<code>&lt;app-child&gt;</code>中添加本地变量<code>#child</code>,点击按钮触发点击事件,通过本地变量调用子组件方法<code>child.addOne()</code>。</p>
<pre><code>&lt;app-child #child&gt;&lt;/app-child&gt;
&lt;button type="button" (click)="child.addOne()"&gt;加1&lt;/button&gt;
</code></pre>
<p>最终展示效果如下,您可以通过 <strong>在线示例</strong> 预览效果和编辑调试:</p>
<p><img src="https://echeverra.cn/wp-content/static/article-img/angularComponentCommunication/85247.gif" alt="" loading="lazy"></p>
<p><strong>说明</strong>:在子组件标签中通过<code>#+变量名</code>的方式新建一个本地变量代表子组件的引用。本地变量方式使用简单明了,但也有局限性,只能在模板html中使用,无法在ts文件中使用。</p>
<h3 id="viewchild方式">@ViewChild方式</h3>
<p>通过<code>@ViewChild</code>装饰器,将子组件注入到父组件。分为4步:</p>
<p>第一步:在子组件<code>child.component.ts</code>中定义<code>count</code>变量和<code>add()</code>方法。</p>
<pre><code>export class ChildComponent {
count: number = 0;
add(num: number) {
    this.count = this.count + num;
}
}
</code></pre>
<p>第二步:在父组件<code>app.component.html</code>中子组件标签<code>&lt;app-child&gt;</code>中添加标签引用<code>#child</code>,点击按钮触发点击事件,执行方法<code>add()</code>。</p>
<pre><code>&lt;app-child #child&gt;&lt;/app-child&gt;
&lt;button type="button" (click)="add(2)"&gt;加2&lt;/button&gt;
</code></pre>
<p>第三步:在父组件<code>app.component.ts</code>中引入<code>ViewChild</code>,<code>@viewchild</code>传入标签引用字符<code>child</code>,由变量<code>child</code>接收。除了使用标签引用<code>child</code>,你也可以通过直接传入子组件<code>ChildComponent</code>实现子组件的引用。</p>
<pre><code>import { Component, ViewChild } from '@angular/core';
import { ChildComponent } from './child/child.component';

export class AppComponent {
// 第一种方法:传入组件引用名child
@ViewChild('child') private child: any;
// 第二种方法:传入组件实例ChildComponent
@ViewChild(ChildComponent) private child: ChildComponent;
}
</code></pre>
<p>第四步:在父组件<code>app.component.ts</code>中方法<code>add()</code>中调用子组件的<code>add()</code>方法。</p>
<pre><code>export class AppComponent {
    add(num: number) {
      this.child.add(num);
    }
}
</code></pre>
<p>最终展示效果如下,您可以通过 <strong>在线示例</strong> 预览效果和编辑调试:</p>
<p><img src="https://echeverra.cn/wp-content/static/article-img/angularComponentCommunication/85536.gif" alt="" loading="lazy"></p>
<p><strong>说明</strong>:<code>@ViewChild</code>的作用是声明对子组件元素的实例引用,意思是通过注入的方式将子组件注入到<code>@ViewChild</code>容器中,你可以想象成依赖注入的方式注入,只不过<code>@ViewChild</code>不能在构造器<code>constructor</code>中注入,<strong>因为<code>@ViewChild()</code>会在<code>ngAfterViewInit()</code>回调函数之前执行</strong>,我们可以测试下:</p>
<pre><code>import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { ChildComponent } from './child/child.component';

export class AppComponent implements AfterViewInit {
@ViewChild('child') private child: any;

constructor() {
    console.log('constructor func', this.child); // undefined
}

ngAfterViewInit() {
    console.log('ngAfterViewInit func', this.child);
}
}
</code></pre>
<p>最终展示效果如下,您可以通过 <strong>在线示例</strong> 预览效果和编辑调试:</p>
<p><img src="https://echeverra.cn/wp-content/static/article-img/angularComponentCommunication/1677472876715.jpg" alt="" loading="lazy"></p>
<p>通过打印结果我们可以看到在构造函数<code>constructor()</code>中,<code>this.child</code>的值为<code>undefined</code>,并没有注入到父组件,但在<code>ngAfterViewInit()</code>生命周期钩子中注入成功了。</p>
<h2 id="不相关组件">不相关组件</h2>
<p>对于不相关联的组件,我们会使用其他中间媒介的方式进行通信,以下不相关组件的通信方式仍适用于父子组件。</p>
<h3 id="service服务方式">service服务方式</h3>
<p>组件间共享一个service服务,那么组件之间就可以通过service实现通信。</p>
<p>示例中我们使用<code>rxjs</code>中的<code>BehaviorSubject</code>,它是<code>Subject</code>的一种变体,可以存储最后一条数据或者初始默认值,并会在订阅时发送其当前值。您可以通过RxJS官网进行了解,当然通过文中的说明,您还是可以了解其具体实现的功能。</p>
<p>我们创建两个不相关的组件<code>A</code>和<code>B</code>,组件<code>A</code>发布数据,组件<code>B</code>接收数据,通过服务文件<code>data.service.ts</code>进行关联实现。</p>
<p>在公共文件目录下创建<code>service</code>服务文件<code>data.service.ts</code>,代码如下:</p>
<pre><code>import { Injectable } from '@angular/core';
// 1.引入
import { BehaviorSubject } from 'rxjs';

@Injectable({
providedIn: 'root',
})
export class DataService {
// 2.创建subject
subject: BehaviorSubject&lt;any&gt; = new BehaviorSubject&lt;any&gt;(0);

constructor() {}
}
</code></pre>
<p>引入<code>BehaviorSubject</code>,创建一个<code>BehaviorSubject</code>, 默认值设为<code>0</code>。 记得在<code>app.module.ts</code>文件中引入公共<code>data.service.ts</code>文件,并声明。</p>
<pre><code>import { DataService } from './data.service';

@NgModule({
providers: ,
})
export class AppModule {}

</code></pre>
<p>创建组件<code>A</code>,用于发布数据,<code>a.component.ts</code>实现代码如下:</p>
<pre><code>import { Component } from '@angular/core';
// 1. 引入
import { DataService } from '../data.service';

@Component({
selector: 'app-a',
templateUrl: './a.component.html',
})
export class AComponent {
// 2. 注册
constructor(public dataService: DataService) {}

inputValue: string = '';

send(): void {
    // 3. 发布
    this.dataService.subject.next(this.inputValue);
}
}
</code></pre>
<p>引入<code>service</code>文件,在<code>constructor()</code>中注入服务依赖<code>dataService</code>,使用服务中<code>subject</code>的<code>next()</code>方法发布广播数据。</p>
<p>创建组件<code>B</code>,用于接收数据,<code>b.component.ts</code>实现代码如下:</p>
<pre><code>import { Component } from '@angular/core';
// 1. 引入
import { Subscription } from 'rxjs';
import { DataService } from '../data.service';

@Component({
selector: 'app-b',
templateUrl: './b.component.html',
})
export class BComponent {
data: any;

// 2. subscription
subscription: Subscription;

constructor(public dataService: DataService) {
    // 3. 订阅
    this.subscription = this.dataService.subject.subscribe((data) =&gt; {
      this.data = data;
    });
}

ngOndestry(): void {
    // 4. 取消订阅
    this.subscription.unsubscribe();
}
}
</code></pre>
<p>引入<code>Subscription</code>,使用服务中<code>subject</code>的<code>subscribe()</code>方法创建一个订阅者,当组件<code>A</code>数据被发布后就可以接收到数据。最后在销毁时记得取消订阅,否则会导致泄露。</p>
<p>最终展示效果如下,您可以通过 <strong>在线示例</strong> 预览效果和编辑调试:</p>
<p><img src="https://echeverra.cn/wp-content/static/article-img/angularComponentCommunication/90232.gif" alt="" loading="lazy"></p>
<p><strong>说明</strong>:示例中组件<code>A</code>和<code>B</code>都引入了同一个服务<code>service</code>,<code>service</code>服务则巧妙利用<code>BehaviorSubject</code>实现数据的发布和订阅,在两个组件中进行数据的通信,是不是没有想象的那么难~</p>
<h3 id="路由传参方式">路由传参方式</h3>
<p>路由传参有多种方式,首先我们新建一个路由模块<code>app-routing.module.ts</code>,代码如下:</p>
<pre><code>import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AppComponent } from './app.component';
import { DetailComponent } from './detail/detail.component';

// 配置路由
const routes: Routes = [
{ path: 'detail', component: DetailComponent },
{ path: 'detail/:id', component: DetailComponent },
];

@NgModule({
imports: ,
exports: ,
})
export class AppRoutingModule {}
</code></pre>
<p>引入路由相关的<code>RouterModule</code>和<code>Routes</code>,引入跳转文章详情组件<code>DetailComponent</code>,配置好路由<code>routes</code>,当路径为<code>detail</code>或<code>detail/:id</code>时,会加载<code>DetailComponent</code>组件,其中<code>:id</code>为占位符,可以在组件<code>ts</code>文件中获取<code>id</code>值。</p>
<p>创建好路由模块我们还需要在根模块<code>app.module.ts</code>中导入。</p>
<pre><code>import { AppRoutingModule } from './app-routing.module';

@NgModule({
declarations: [...],
imports: ,
providers: ,
bootstrap: ,
})
export class AppModule {}
</code></pre>
<p>在<code>app.component.html</code>文件中添加<code>&lt;router-outlet&gt;&lt;/router-outlet&gt;</code>路由占位符,Angular框架会根据当前的路由器状态将不同组件动态填充它。</p>
<p>配置完路由准备工作,我们来具体看下有哪些路由传参方式。</p>
<h4 id="路由路径传参">路由路径传参</h4>
<p>路由路径中传参,链接形式为:<code>https://ip/detail/1</code>。</p>
<p>在<code>app.component.html</code>中使用路由指令<code>routerLink</code>的方式在路由路径中传参。</p>
<pre><code>&lt;a ="['/detail',1]"&gt;
1.文章1(路由路径中传参,链接:https://ip/detail/1)
&lt;/a&gt;
</code></pre>
<p>在<code>detail</code>组件<code>detail.component.ts</code>中使用当前路由对象<code>ActivatedRoute</code>获取路由传递的参数。</p>
<pre><code>import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Params } from '@angular/router';

@Component({
selector: 'app-detail',
templateUrl: './detail.component.html',
})
export class DetailComponent implements OnInit {
id: any;

constructor(private routeInfo: ActivatedRoute) {}

ngOnInit() {
    // 获取路由参数方法
    this.routeInfo.params.subscribe((params: Params) =&gt; {
      this.id = params['id'];
    });
}
}

</code></pre>
<h4 id="查询参数传参">查询参数传参</h4>
<p>查询参数中传参,链接形式为:<code>https://ip/detail?id=2</code>。</p>
<p>在<code>app.component.html</code>中同样使用路由指令<code>routerLink</code>,在<code>queryParams</code>查询参数中传递数据。</p>
<pre><code>&lt;a ="['/detail']" ="{ id: 2 }"&gt;
2. 文章2(查询参数中传参,链接:https://ip/detail?id=2)
&lt;/a&gt;
</code></pre>
<p>在<code>detail</code>组件<code>detail.component.ts</code>中使用当前路由对象<code>ActivatedRoute</code>获取路由传递的参数。</p>
<pre><code>import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Params } from '@angular/router';

@Component({
selector: 'app-detail',
templateUrl: './detail.component.html',
})
export class DetailComponent implements OnInit {
id: any;

constructor(private routeInfo: ActivatedRoute) {}

ngOnInit() {
    // 获取路由参数方法(params改为queryParams)
    this.routeInfo.queryParams.subscribe((params: Params) =&gt; {
      this.id = params['id'];
    });
}
}

</code></pre>
<p>仔细观察会发现,第一种路由路径中传参使用的是<code>this.routeInfo.queryParams</code>获取数据,而第二种查询参数中传参使用的是<code>this.routeInfo.queryParams</code>,一定要注意这个区别。</p>
<h4 id="路由配置传参">路由配置传参</h4>
<p>除了在<code>app.component.html</code>中使用路由指令<code>routerLink</code>,我们还可以在<code>app.component.ts</code>文件中通过路由配置中传参。</p>
<p>在<code>app.component.html</code>文件中绑定两个点击方法<code>toArticle3()</code>和<code>toArticle4()</code>。</p>
<pre><code>&lt;a (click)="toArticle3()"&gt;
3. 文章3(路由配置中传参,链接:https://ip/detail/3)&lt;/a&gt;

&lt;a (click)="toArticle4()"&gt;
4. 文章4(路由配置中传参,链接:https://ip/detail?id=4)&lt;/a&gt;
</code></pre>
<p>在<code>app.component.ts</code>文件中通过路由<code>Router</code>的<code>navigate()</code>方法实现跳转。</p>
<pre><code>import { Component } from '@angular/core';
import { Router } from '@angular/router';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {

constructor(private router: Router) {}

toArticle3() {
    // 路由跳转文章3
    this.router.navigate(['/detail', 3]);
}

toArticle4() {
    // 路由跳转文章4
    this.router.navigate(['/detail'], { queryParams: { id: 4 } });
}
}
</code></pre>
<p>虽然是通过路由配置传参跳转,但我们仍然可以发现,文章3和文章1的跳转链接一致,文章4和文章2的跳转链接一致,本质上也是路由路径传参和查询参数传参。所以在<code>detail.component.ts</code>中,接收路由参数的方法是一致的。</p>
<pre><code>import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Params } from '@angular/router';

@Component({
selector: 'app-detail',
templateUrl: './detail.component.html',
})
export class DetailComponent implements OnInit {
id: any;

constructor(private routeInfo: ActivatedRoute) {}

ngOnInit() {
    // 文章3路由参数获取(params)
    this.routeInfo.params.subscribe((params: Params) =&gt; {
      this.id = params['id'];
    });

    // 文章4路由参数获取(queryParams)
    this.routeInfo.queryParams.subscribe((params: Params) =&gt; {
      this.id = params['id'];
    });
}
}
</code></pre>
<p>最终展示效果如下,您可以通过 <strong>在线示例</strong> 预览效果和编辑调试:</p>
<p><img src="https://echeverra.cn/wp-content/static/article-img/angularComponentCommunication/144920.gif" alt="" loading="lazy"></p>
<p>这里需要说明下,在线示例中点击文章<code>url</code>并未发生改变,这是因为stackblitz工具机制的问题,你可以点击在线示例界面的<code>Open in New Tab</code>按钮,在单独页面打开可规避该问题。</p>
<p><strong>延伸</strong>:示例中的获取路由参数都是使用<code>subscribe</code>参数订阅的方式,还有一种<code>snapshot</code>参数快照的方式。如获取文章1路由参数写法为:<code>this.id = this.routeInfo.snapshot.params['id'];</code>,获取文章2路由参数写法为:<code>this.id = this.routeInfo.snapshot.queryParams['id'];</code>,可以看到同样是<code>params</code>与<code>queryParams</code>的区别。</p>
<p><code>snapshot</code>参数快照和<code>subscribe</code>参数订阅两者的区别在于,当路由地址不变的情况下,若参数变化,<code>snapshot</code>参数快照获取的参数值不变,<code>subscribe</code>参数订阅获取的参数值会变化。</p>
<p>我们使用<code>snapshot</code>参数快照测试一下文章1和文章3,效果如下:</p>
<p><img src="https://echeverra.cn/wp-content/static/article-img/angularComponentCommunication/145212.gif" alt="" loading="lazy"></p>
<p>那么<code>snapshot</code>参数快照获取的参数为什么不发生变化了呢?这是由于第一次点击文章1跳转<code>detail</code>组件,<code>constructor()</code>和<code>ngOnInit()</code>会被调用一次,再次点击文章3,由于<code>detail</code>组件页面已经被创建了,<code>ngOnInit()</code>方法不会再次被调用,所以路由参数<code>id</code>依然保存着第一次被创建时候的值<code>1</code>。</p>
<h3 id="localstorage方式">LocalStorage方式</h3>
<p>当然你也可以使用本地存储这种比较通用的方式在组件间通信。</p>
<p>创建<code>C</code>组件<code>c.component.ts</code>将数据存储到<code>key</code>为<code>cValue</code>的<code>localStorage</code>中,代码如下:</p>
<pre><code>import { Component } from '@angular/core';

@Component({
selector: 'app-c',
templateUrl: './c.component.html',
})
export class CComponent {
constructor() {}

inputValue: string = '';

send(): void {
    // 存储数据
    window.localStorage.setItem('cValue', this.inputValue);
}
}
</code></pre>
<p>创建<code>D</code>组件<code>d.component.ts</code>获取<code>localStorage</code>中<code>cValue</code>的值。</p>
<pre><code>import { Component } from '@angular/core';

@Component({
selector: 'app-d',
templateUrl: './d.component.html',
})
export class DComponent {
data: any;

constructor() {}

getValue() {
    // 获取数据
    this.data = window.localStorage.getItem('cValue');
}
}
</code></pre>
<p>最终展示效果如下,您可以通过 <strong>在线示例</strong> 预览效果和编辑调试:</p>
<p><img src="https://echeverra.cn/wp-content/static/article-img/angularComponentCommunication/145354.gif" alt="" loading="lazy"></p>
<p><strong>注</strong>:这里没有使用<code>sessionStorage</code>存储是因为<code>localStorage</code>生命周期是永久的,而<code>sessionStorage</code>生命周期仅为当前标签页,如果两个组件分别在两个标签页,那么使用<code>sessionStorage</code>是无法实现通信的。</p>
<h3 id="服务端通信方式">服务端通信方式</h3>
<p>最后一种通信方式是借助后台传输数据,如<code>A</code>组件调接口发送数据<code>data</code>存储到后台,再由<code>B</code>组件调接口获取数据<code>data</code>,实现数据通信,这里就不做演示了。</p>
<h2 id="总结">总结</h2>
<p>Angular组件间的通信方式是多种多样的,对于不同情景我们可以采用合适的方式进行通信。</p>
<p>本文每个示例的重点我都有详细的说明,并延展一些相关知识。示例都是我自己一点点亲手敲的,从0到1研究示例实现方案,虽然花费了很长时间,但加深巩固了知识,之前忽略的一些知识细节也得到了补充,建议大家在学习的同时最好也能动手实现。</p>
<p>好啦,以上就是Angular组件间各种通信方式的所有内容,希望对你有所帮助,如有问题可通过我的博客https://echeverra.cn或微信公众号echeverra联系我。</p>
<p>你学“废”了么?</p>
<p>(完)</p>


</div>
<div id="MySignature" role="contentinfo">
    <p>本文来自博客园,作者:echeverra,转载请注明原文链接:https://www.cnblogs.com/echeverra/p/component-communication.html</p><br><br>
来源:https://www.cnblogs.com/echeverra/p/component-communication.html
頁: [1]
查看完整版本: 玩转Angular系列:组件间各种通信方式详解