Angular 组件之间的交互的示例代码
这篇文章主要介绍了Angular 组件之间的交互的示例代码,根据数据的传递方向,分为父组件向子组件传递、子组件向父组件传递及通过服务传递三种交互方法。非常具有实用价值,需要的朋友可以参考下
在Angular应用开发中,组件可以说是随处可见的。本篇文章将介绍几种常见的组件通讯场景,也就是让两个或多个组件之间交互的方法。
根据数据的传递方向,分为父组件向子组件传递、子组件向父组件传递及通过服务传递三种交互方法。
父组件向子组件传递
子组件通过@Input装饰器定义输入属性,然后父组件在引用子组件的时候通过这些输入属性向子组件传递数据,子组件可通过setter或ngOnChanges()来截听输入属性值的变化。
先定义两个组件,分别为子组件DemoChildComponent和父组件DemoParentComponent.
子组件:
@Component({ selector: 'demo-child', template: ` <p>{{paramOne}}</p> <p>{{paramTwo}}</p> ` }) export class DemoChildComponent { @Input() paramOne: any; // 输入属性1 @Input() paramTwo: any; // 输入属性2 }
子组件通过@Input()定义输入属性paramOne和paramTwo(属性值可以为任意数据类型)
父组件:
@Component({ selector: 'demo-parent', template: ` <demo-child [paramOne]='paramOneVal' [paramTwo]='paramTwoVal'></demo-child> ` }) export class DemoParentComponent { paramOneVal: any = '传递给paramOne的数据'; paramTwoVal: any = '传递给paramTwo的数据'; }
父组件在其模板中通过选择器demo-child引用子组件DemoChildComponent,并通过子组件的两个输入属性paramOne和paramTwo向子组件传递数据,最后在子组件的模板中就显示传递给paramOne的数据和传递给paramTwo的数据这两行文本。
通过 setter 截听输入属性值的变化
在实际应用中,我们往往需要在某个输入属性值发生变化的时候做相应的操作,那么此时我们需要用到输入属性的 setter 来截听输入属性值的变化。
我们将子组件DemoChildComponent进行如下改造:
@Component({ selector: 'demo-child', template: ` <p>{{paramOneVal}}</p> <p>{{paramTwo}}</p> ` }) export class DemoChildComponent { private paramOneVal: any; @Input() set paramOne (val: any) { // 输入属性1 this.paramOneVal = val; // dosomething }; get paramOne () { return this.paramOneVal; }; @Input() paramTwo: any; // 输入属性2 }
在上面的代码中,我们可以看到通过paramOne属性的 setter 将拦截到的值val赋值给内部私有属性paramOneVal,达到父组件传递数据给子组件的效果。当然,最重要的是,在 setter 里面你可以做更多的其它操作,程序的灵活性就更强了。
通过ngOnChanges()来截听输入属性值的变化
通过 setter 截听输入属性值的变化的方法只能对单个属性值变化进行监视,如果需要监视多个、交互式输入属性的时候,这种方法就显得力不从心了。而通过使用 OnChanges 生命周期钩子接口的 ngOnChanges() 方法(当组件通过@Input装饰器显式指定的那些变量的值变化时调用)就可以实现同时监视多个输入属性值的变化。
在子组件DemoChildComponent新增ngOnChanges:
@Component({ selector: 'demo-child', template: ` <p>{{paramOneVal}}</p> <p>{{paramTwo}}</p> ` }) export class DemoChildComponent implements OnChanges { private paramOneVal: any; @Input() set paramOne (val: any) { // 输入属性1 this.paramOneVal = val; // dosomething }; get paramOne () { return this.paramOneVal; }; @Input() paramTwo: any; // 输入属性2 ngOnChanges(changes: {[propKey: string]: SimpleChange}) { for (let propName in changes) { // 遍历changes let changedProp = changes[propName]; // propName是输入属性的变量名称 let to = JSON.stringify(changedProp.currentValue); // 获取输入属性当前值 if (changedProp.isFirstChange()) { // 判断输入属性是否首次变化 console.log(`Initial value of ${propName} set to ${to}`); } else { let from = JSON.stringify(changedProp.previousValue); // 获取输入属性先前值 console.log(`${propName} changed from ${from} to ${to}`); } } } }
新增的ngOnChanges方法接收的参数changes是以输入属性名称为键、值为SimpleChange的对象,SimpleChange对象含有当前输入属性是否第一次变化、先前值、当前值等属性。因此在ngOnChanges方法中通过遍历changes对象可监视多个输入属性值并进行相应的操作。
获取父组件实例
前面介绍的都是子组件通过@Input装饰器定义输入属性,这样父组件可通过输入属性将数据传递给子组件。
当然,我们可以想到一种更主动的方法,那就是获取到父组件实例,然后调用父组件的某个属性或方法来获取需要的数据。考虑到每个组件的实例都会添加到注入器的容器里,因此可通过依赖注入来找到父组件的示例。
子组件获取父组件实例相比于父组件获取子组件实例(直接通过模板变量、@ViewChild或@ViewChildren获取)要麻烦一些。
要在子组件中获取父组件的实例,有两种情况:
已知父组件的类型
这种情况可以直接通过在构造函数中注入DemoParentComponent来获取已知类型的父组件引用,代码示例如下:
@Component({ selector: 'demo-child', template: ` <p>{{paramOne}}</p> <p>{{paramTwo}}</p> ` }) export class DemoChildComponent { paramOne: any; paramTwo: any; constructor(public demoParent: DemoParentComponent) { // 通过父组件实例demoParent获取数据 this.paramOne = demoParent.paramOneVal; this.paramTwo = demoParent.paramTwoVal; } }
未知父组件的类型
一个组件可能是多个组件的子组件,有时候无法直接知道父组件的类型,在Angular中,可通过类—接口(Class-Interface)的方式来查找,即让父组件通过提供一个与类—接口标识同名的别名来协助查找。
首先创建DemoParent抽象类,它只声明了paramOneVal和paramTwoVal属性,没有实现(赋值),示例代码如下:
export abstract class DemoParent { paramOneVal: any; paramTwoVal: any; }
然后在父组件DemoParentComponent的providers元数据中定义一个别名 Provider,用 useExisting 来注入父组件DemoParentComponent的实例,代码示例如下:
@Component({ selector: 'demo-parent', template: ` <demo-child [paramOne]='paramOneVal' [paramTwo]='paramTwoVal'></demo-child> `, providers: [{provider: DemoParent, useExisting: DemoParentComponent}] }) export class DemoParentComponent implements DemoParent { paramOneVal: any = '传递给paramOne的数据'; paramTwoVal: any = '传递给paramTwo的数据'; }
然后在子组件中就可通过DemoParent这个标识找到父组件的示例了,示例代码如下:
@Component({ selector: 'demo-child', template: ` <p>{{paramOne}}</p> <p>{{paramTwo}}</p> ` }) export class DemoChildComponent { paramOne: any; paramTwo: any; constructor(public demoParent: DemoParent) { // 通过父组件实例demoParent获取数据 this.paramOne = demoParent.paramOneVal; this.paramTwo = demoParent.paramTwoVal; } }
子组件向父组件传递
依然先定义两个组件,分别为子组件DemoChildComponent和父组件DemoParentComponent.
子组件:
@Component({ selector: 'demo-child', template: ` <p>子组件DemoChildComponent</p> ` }) export class DemoChildComponent implements OnInit { readyInfo: string = '子组件DemoChildComponent初始化完成!'; @Output() ready: EventEmitter = new EventEmitter<any>(); // 输出属性 ngOnInit() { this.ready.emit(this.readyInfo); } }
父组件:
@Component({ selector: 'demo-parent', template: ` <demo-child (ready)="onReady($event)" #demoChild></demo-child> <p> <!-- 通过本地变量获取readyInfo属性,显示:子组件DemoChildComponent初始化完成! --> readyInfo: {{demoChild.readyInfo}} </p> <p> <!-- 通过组件类获取子组件示例,然后获取readyInfo属性,显示:子组件DemoChildComponent初始化完成! --> readyInfo: {{demoChildComponent.readyInfo}} </p> ` }) export class DemoParentComponent implements AfterViewInit { // @ViewChild('demoChild') demoChildComponent: DemoChildComponent; // 通过模板别名获取 @ViewChild(DemoChildComponent) demoChildComponent: DemoChildComponent; // 通过组件类型获取 ngAfterViewInit() { console.log(this.demoChildComponent.readyInfo); // 打印结果:子组件DemoChildComponent初始化完成! } onReady(evt: any) { console.log(evt); // 打印结果:子组件DemoChildComponent初始化完成! } }
父组件监听子组件的事件
子组件暴露一个 EventEmitter 属性,当事件发生时,子组件利用该属性 emits(向上弹射)事件。父组件绑定到这个事件属性,并在事件发生时作出回应。
在上面定义好的子组件和父组件,我们可以看到:
子组件通过@Output()定义输出属性ready,然后在ngOnInit中利用ready属性的 emits(向上弹射)事件。
父组件在其模板中通过选择器demo-child引用子组件DemoChildComponent,并绑定了一个事件处理器(onReady()),用来响应子组件的事件($event)并打印出数据(onReady($event)中的$event是固定写法,框架(Angular)把事件参数(用 $event 表示)传给事件处理方法)。
父组件与子组件通过本地变量(模板变量)互动
父组件不能使用数据绑定来读取子组件的属性或调用子组件的方法。但可以在父组件模板里,新建一个本地变量来代表子组件,然后利用这个变量来读取子组件的属性和调用子组件的方法。
在上面定义好的子组件和父组件,我们可以看到:
父组件在模板demo-child标签上定义了一个demoChild本地变量,然后在模板中获取子组件的属性:
<p> <!-- 获取子组件的属性readyInfo,显示:子组件DemoChildComponent初始化完成! --> readyInfo: {{demoChild.readyInfo}} </p>
父组件调用@ViewChild()
本地变量方法是个简单便利的方法。但是它也有局限性,因为父组件-子组件的连接必须全部在父组件的模板中进行。父组件本身的代码对子组件没有访问权。
如果父组件的类需要读取子组件的属性值或调用子组件的方法,就不能使用本地变量方法。
当父组件类需要这种访问时,可以把子组件作为 ViewChild,注入到父组件里面。
在上面定义好的子组件和父组件,我们可以看到:
父组件在组件类中通过@ViewChild()获取到子组件的实例,然后就可以在模板或者组件类中通过该实例获取子组件的属性:
<p> <!-- 通过组件类获取子组件示例,然后获取readyInfo属性,显示:子组件DemoChildComponent初始化完成! --> readyInfo: {{demoChildComponent.readyInfo}} </p>
ngAfterViewInit() { console.log(this.demoChildComponent.readyInfo); // 打印结果:子组件DemoChildComponent初始化完成! }
通过服务传递
Angular的服务可以在模块注入或者组件注入(均通过providers注入)。
在模块中注入的服务在整个Angular应用都可以访问(除惰性加载的模块)。
在组件中注入的服务就只能该组件和其子组件进行访问,这个组件子树之外的组件将无法访问该服务或者与它们通讯。
下面的示例就以在组件中注入的服务来进行父子组件之间的数据传递:
通讯的服务:
@Injectable() export class CallService { info: string = '我是CallService的info'; }
父组件:
@Component({ selector: 'demo-parent', template: ` <demo-child></demo-child> <button (click)="changeInfo()">父组件改变info</button> <p> <!-- 显示:我是CallService的info --> {{callService.info}} </p> `, providers: [CallService] }) export class DemoParentComponent { constructor(public callService: CallService) { console.log(callService.info); // 打印结果:我是CallService的info } changeInfo() { this.callService.info = '我是被父组件改变的CallService的info'; } }
子组件:
@Component({ selector: 'demo-child', template: ` <button (click)="changeInfo()">子组件改变info</button> ` }) export class DemoChildComponent { constructor(public callService: CallService) { console.log(callService.info); // 打印结果:我是CallService的info } changeInfo() { this.callService.info = '我是被子组件改变的CallService的info'; } }
上面的代码中,我们定义了一个CallService服务,在其内定义了info属性,后面将分别在父子组件通过修改这个属性的值达到父子组件互相传递数据的目的。
然后通过DemoParentComponent的providers元数据数组提供CallService服务的实例,并通过构造函数分别注入到父子组件中。
此时,通过父组件改变info按钮或子组件改变info按钮在父组件或子组件中改变CallService服务的info属性值,然后在页面可看到改变之后对应的info属性值。
上面是我整理给大家的,希望今后会对大家有帮助。
相关文章:
jQuery实现文字超过1行、2行或规定的行数时自动加省略号的方法
以上是Angular 组件之间的交互的示例代码的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

热门话题

Angular.js是一种可自由访问的JavaScript平台,用于创建动态应用程序。它允许您通过扩展HTML的语法作为模板语言,以快速、清晰地表示应用程序的各个方面。Angular.js提供了一系列工具,可帮助您编写、更新和测试代码。此外,它还提供了许多功能,如路由和表单管理。本指南将讨论在Ubuntu24上安装Angular的方法。首先,您需要安装Node.js。Node.js是一个基于ChromeV8引擎的JavaScript运行环境,可让您在服务器端运行JavaScript代码。要在Ub

Python函数介绍:exec函数的介绍及示例引言:在Python中,exec是一种内置函数,它用于执行存储在字符串或文件中的Python代码。exec函数提供了一种动态执行代码的方式,使得程序可以在运行时根据需要生成、修改和执行代码。本文将介绍exec函数的使用方法,并给出一些实际的代码示例。exec函数的使用方法:exec函数的基本语法如下所示:exec

Go语言的缩进规范及示例Go语言是一种由Google开发的编程语言,它以简洁、清晰的语法着称,其中缩进规范在代码的可读性和美观性方面起着至关重要的作用。本文将介绍Go语言的缩进规范,并通过具体的代码示例进行详细说明。缩进规范在Go语言中,缩进使用制表符(tab)而非空格。每级缩进为一个制表符,通常设置为4个空格的宽度。这样的规范统一了代码风格,使得团队合作编

在win11系统中,我们可以通过打开分屏交互来让多个显示器使用同一款系统,共同操作,但是很多朋友不知道分屏交互怎么开启,其实只要在系统设置中找到显示器就可以了,下面一起来学习一下吧。win11分屏交互怎么打开1、点击开始菜单,找到其中的“设置”2、然后在其中找到“系统”设置。3、进入系统设置后,在左侧选择“显示”4、接着在右边的多显示器中选择“扩展这些显示器”即可。

Oracle中的DECODE函数是一种条件表达式,常用于在查询语句中根据不同的条件返回不同的结果。本文将详细介绍DECODE函数的语法、用法和示例代码。一、DECODE函数语法DECODE(expr,search1,result1[,search2,result2,...,default])expr:要进行比较的表达式或字段。search1,

Python函数介绍:abs函数的用法和示例一、abs函数的用法介绍在Python中,abs函数是一个内置函数,用于计算给定数值的绝对值。它可以接受一个数字参数,并返回该数字的绝对值。abs函数的基本语法如下:abs(x)其中,x是要计算绝对值的数值参数,可以是整数或浮点数。二、abs函数的示例下面我们将通过一些具体的示例来展示abs函数的用法:示例1:计算

Angular框架中组件的默认显示行为不是块级元素。这种设计选择促进了组件样式的封装,并鼓励开发人员有意识地定义每个组件的显示方式。通过显式设置CSS属性 display,Angular组件的显示可以完全控制,从而实现所需的布局和响应能力。

Vue3+TS+Vite开发技巧:如何与后端API进行交互引言:在网页应用开发中,前端与后端之间的数据交互是一个非常重要的环节。Vue3作为一种流行的前端框架,与后端API进行交互的方式也有很多种。本文将介绍如何使用Vue3+TypeScript+Vite开发环境来与后端API进行交互,并通过代码示例来加深理解。一、使用Axios发送请求Axios是
