Angular 学习笔记组件篇

组件交互

父组件传值给子组件

在父子组件的应用当中,组件通讯是非常重要的一环.现有两个组件,现在我们尝试将父类的输入框值传给子类的输入框值.在输入内容之后点击按钮即可完成.接下来我们分析下这个流程:

  1. 父组件取得值并将值与数据源中的 fatherValue1进行双向绑定
  2. 点击按钮后触发数据源事件,将 fatherValue1的值赋值给 childValue1
  3. 在 child-communication 标签上存在从数据源到视图的单向绑定,Angular变更检查发现 childValue1 的值不一样了(初值为空),将 childValue1的值流入子组件,子组件利用 ngModel 对 childValue1进行了双向绑定,因此修改了子组件的输入框值.

父组件html+ts

	<h1>我是父组件</h1>
    <input nz-input class="input" [(ngModel)]="fatherValue1" placeholder="父组件的输入框">
    <button (click)="transferData()" nz-button nzType="primary">传值给子组件</button>
    <child-communication [childValue1]="childValue1"></child-communication>
  fatherValue1;
    childValue1;
    transferData() {
        this.childValue1 = this.fatherValue1;
    }

子组件html+ts

	<h1>我是子组件</h1>
    <input nz-input class="input" [(ngModel)]="childValue1" name="childValue1" placeholder="子组件的输入框">
@Input() childValue1: string;

这里思考一个问题,如果在第一次传值之后,修改子组件的值再按传值按钮,会发现父组件并不能修改子组件的值,请思考一下这是为什么?
这是因为当第一次传值时, 父组件 childValue1与 fatherValue1是一致的,在子组件修改内容之后,虽然修改了子组件内部的 childValue1 ,但是父组件的 childValue1与 fatherValue1还是一样的.也就导致Angular的变更检查结果为未发生变化,也就导致父组件未能将值流入子组件.
既然未变更值他就无法将数据流入子组件,那么我们只要在数据源事件中,每次都重置下 childValue1再赋值,不就发生了数据变更吗?即可达到每次点击都变更的效果.

类调用

@ViewChild(ChildCommunicationComponent) private childComponent: ChildCommunicationComponent;

在父组件的数据源中,对子组件的引用使用的是 类调用,即参数都是子组件的类名.所以子组件有个输入框,点击子组件的按钮可以正常弹出值.但是点击父类,也能弹出信息,但是却无值

实例调用

@ViewChild('child') private childComponent2: ChildCommunicationComponent;

父组件html+ts

  	<h1>我是父组件</h1>
    <button (click)="callChildFunction3()" nz-button nzType="primary">调用子组件方法</button>
    <child-communication #child></child-communication>
	@ViewChild('child') private childComponent2: ChildCommunicationComponent;
    callChildFunction3() {
        this.childComponent2.childFunction3();
    }

子组件html+ts

 	<h1>我是子组件</h1>
    <input nz-input class="input" [(ngModel)]="childValue3" name="childValue3" placeholder="子组件的输入框">
    <button (click)="childFunction3()" nz-button nzType="primary">调用方法</button>
 	childValue3;
    childFunction3() {
        this.messageService.info(this.childValue3);
    }

子组件传值给父组件

在父组件传值给子组件的时候,其实是通过指令的方式完成的.但是使用指令的前提,是被传值者是一个标签,这符合了父组件传值给子组件的条件.
但是子组件显然不可能包含父组件的标签,所以并不能通过这种方式完成传值.

父组件html+ts

    <h1>我是父组件</h1>
    <input nz-input class="input" [(ngModel)]="name" placeholder="姓名">
    <input nz-input class="input" [(ngModel)]="bornYear" placeholder="出生年月">
    <child-communication (event)="showInfo($event)"></child-communication>
    name;
    bornYear;
    showInfo($event) {
        this.name = $event.name;
        this.bornYear = $event.bornYear;
    }

子组件html+ts

    <h1>我是子组件</h1>
    <input nz-input class="input" [(ngModel)]="name" name="name" placeholder="姓名">
    <input nz-input class="input" [(ngModel)]="bornYear" name="bornYear" placeholder="出生年月">
    <button (click)="childFunction4()" nz-button nzType="primary">传值给父组件</button> 
    @Output() event = new EventEmitter<any>();
    name = 'Eve';
    bornYear = '1995';
    childFunction4() {
        this.event.emit(
            {
                name: this.name,
                bornYear: this.bornYear
            }
        );
    }

通过服务进行通讯

在组件通讯中,还有一种方式叫做服务(service).这种方式较为复杂,涉及RxJS内容,具体步骤如下:

  1. 定义一个service,定义父子Subject变量,转为Observable后再保存变量,创建函数事件发射器
  2. 在父组件中, 在 providers中提供服务的实例,在构造函数中对子组件发起订阅
  3. 在子组件中,重复上一步,只是没有使用 providers,因为是子组件,可以自动获取父组件的服务实例
  4. 点击按钮(无论是父的还是子的),都会触发服务中的 next()函数,发送新值给订阅者,订阅者触发订阅操作,将新值赋值给自身的成员变量,之后的刷新试图操作属于双向绑定,与通讯无关.

Service

    import { Injectable } from '@angular/core';
    import { Subject } from 'rxjs';

    @Injectable()
    export class CommunicationService {
        // 声明两个Subject并定义接收数据类型,在本案例中是一个对象
        private father = new Subject<{ drink, eat }>();
        private child = new Subject<{ drink, eat }>();
        // 将Subject转化为Observable
        father$ = this.father.asObservable();
        child$ = this.child.asObservable();
        /* 将变化的值,发送给订阅者 */
        fatherSend(value: { drink, eat }) {
            this.father.next(value);
        }
        childSend(value: { drink, eat }) {
            this.child.next(value);
        }
    }

父组件html+ts

    <h1>父组件</h1>
    <input nz-input class="input" [(ngModel)]="drink" name="drink" placeholder="最爱喝的饮料">
    <input nz-input class="input" [(ngModel)]="eat" name="eat" placeholder="最爱吃的甜点">
    <button (click)="transferDataByService()" nz-button nzType="primary">传值给子组件</button>
    <child-communication></child-communication>
    import { CommunicationService } from './service/communication.service';
    import { Subscription } from 'rxjs';

    @Component({
        templateUrl: './component-communication.component.html',
        styleUrls: ['./component-communication.component.less'],
        providers: [CommunicationService]
    })
    export class ComponentCommunicationComponent implements OnDestroy {
        subscription: Subscription;
        constructor(
            private communicationService: CommunicationService
        ) {
            this.subscription = communicationService.child$.subscribe(value => {
                this.drink = value.drink;
                this.eat = value.eat;
            });
        }
        drink = '奶茶';
        eat = '泡芙';
        transferDataByService() {
            this.communicationService.fatherSend({ drink: this.drink, eat: this.eat });
        }
        ngOnDestroy() {
            this.subscription.unsubscribe();
        }
    }

子组件html+ts

    <h1>子组件</h1>
    <input nz-input class="input" [(ngModel)]="drink" name="drink" placeholder="最爱喝的饮料">
    <input nz-input class="input" [(ngModel)]="eat" name="eat" placeholder="最爱吃的甜点">
    <button (click)="transferDataByService()" nz-button nzType="primary">传值给父组件</button>
    import { Subscription } from 'rxjs';

    @Component({
        selector: 'child-communication',
        templateUrl: './child-communication.component.html',
        styleUrls: ['./child-communication.component.less']
    })
    export class ChildCommunicationComponent implements OnDestroy {
        subscription: Subscription;
        constructor(private communicationService: CommunicationService) {
            this.subscription = communicationService.father$.subscribe(value => {
                this.drink = value.drink;
                this.eat = value.eat;
            });
        }
        drink;
        eat;
        transferDataByService() {
            this.communicationService.childSend({ drink: this.drink, eat: this.eat });
        }
        ngOnDestroy() {
            this.subscription.unsubscribe();
        }
    }
    

组件样式

在父组件当中定义了样式 bgColor,将背景颜色设置为红色,在子组件当中定义了样式 color将字体颜色设置为蓝色.在父子组件的内容中,同时应用了这两种样式,通过效果可以发现,父子组件样式互相并不影响.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值