본 글에서는 Angular 컴포넌트 간의 상호작용을 위한 샘플 코드를 주로 소개하며, 데이터 전송 방향에 따라 상위 컴포넌트에서 하위 컴포넌트로, 하위 컴포넌트에서 상위 컴포넌트로, 서비스 전달의 세 가지 상호작용 방식으로 구분됩니다. 실용성이 매우 좋습니다. 필요한 친구들이 참고하면 됩니다
Angular 애플리케이션 개발에서는 컴포넌트가 어디에나 있다고 할 수 있습니다. 이 문서에서는 둘 이상의 구성 요소 간의 상호 작용 방법인 몇 가지 일반적인 구성 요소 통신 시나리오를 소개합니다.
데이터 전송 방향에 따라 상위 컴포넌트에서 하위 컴포넌트로, 하위 컴포넌트에서 상위 컴포넌트로, 서비스 전달의 세 가지 상호작용 방식으로 구분됩니다.
상위 구성 요소는
을 하위 구성 요소에 전달합니다. 그런 다음 하위 구성 요소는 하위 구성 요소를 참조할 때 이러한 입력 속성을 통해 하위 구성 요소에 데이터를 전달합니다. 하위 구성 요소는 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的数据'; }
부모 구성 요소는 템플릿의 선택기 데모-하위를 통해 하위 구성 요소 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 }
위 코드에서 가로채는 값 val이 paramOne 속성의 설정자를 통해 내부 전용 속성 paramOneVal에 할당되는 것을 볼 수 있습니다. 상위 항목에 도달 구성 요소가 하위 구성 요소에 데이터를 전달하는 효과입니다. 물론 가장 중요한 것은 setter에서 더 많은 다른 작업을 수행할 수 있어 프로그램이 더욱 유연해진다는 것입니다.
ngOnChanges()를 사용하여 입력 속성 값의 변경 사항을 가로채기
setter를 통해 입력 속성 값의 변경 사항을 가로채는 방법은 단일 속성 값의 변경 사항만 모니터링할 수 있으며, 여러 대화형으로 모니터링해야 하는 경우에만 가능합니다. 입력 속성의 경우 이 방법은 부적절한 것 같습니다. OnChanges 라이프 사이클 후크 인터페이스(@Input 데코레이터를 통해 구성 요소에 의해 명시적으로 지정된 변수 값이 변경될 때 호출됨)의 ngOnChanges() 메서드를 사용하면 여러 입력 속성 값의 변경 사항을 동시에 모니터링할 수 있습니다.
하위 구성 요소 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 메서드에서 수신한 매개변수 변경 사항은 입력 속성 이름이 키이고 값이 SimpleChange인 개체입니다. 현재 입력 속성이 변경사항, 이전 값, 현재 값 등과 같은 첫 번째 속성인지 여부 따라서 ngOnChanges 메소드에서는 여러 입력 속성 값을 모니터링하고 변경 객체를 순회하여 해당 작업을 수행할 수 있습니다.
상위 구성 요소 인스턴스 가져오기
이전 소개에서는 하위 구성 요소가 @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에서 직접 알 수 없으며 클래스 인터페이스 메서드를 통해 검색할 수 있습니다. 즉, 상위 구성 요소는 클래스 인터페이스 식별자와 동일한 이름을 가진 별칭을 제공하여 검색을 지원할 수 있습니다.
먼저 구현(할당) 없이 paramOneVal 및 paramTwoVal 속성만 선언하는 DemoParent 추상 클래스를 만듭니다. 샘플 코드는 다음과 같습니다.
export abstract class DemoParent { paramOneVal: any; paramTwoVal: any; }
그런 다음 상위 공급자의 공급자 메타데이터에 별칭 공급자를 정의합니다. 구성 요소 DemoParentComponent, 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 중국어 웹사이트의 기타 관련 기사를 참조하세요!