网站首页 » 前端开发 » Angular 2+ » Angular 2+ 组件间的数据交互
上一篇:
下一篇:

Angular 2+ 组件间的数据交互

组件之间的交互

通过输入型绑定把数据从父组件传到子组件

这种数据交互比较简单,直接通过属性传入子组件,然后在子组件通过 @Input 来获取值,代码如下:

parent.component.rs
import { Component } from '@angular/core';

@Component({
    selector: 'parent-component',
    template: `<child-component *ngFor="let site of parentSites" [site]="site"></child-component>`
})
export class ParentComponent {
    title = "parent";
    parentSites: any = [
        {
            name: "云库网",
            domain: "http://yunkus.com"
        },
        {
            name: "朝夕熊博客",
            domain: "http://zhaoxixiong.com"
        }
    ];
}
child.component.ts
import { Component, Input } from '@angular/core';

@Component({
    selector: 'child-component',
    template: `
    <div>
        <h3>{{site.name}}</h3>
        <p>{{site.domain}}</p>
    </div>
    `
})

export class ChildComponent {
    title = "child component here";
    @Input() site: any;
}

怎么简单怎么来,只要能说明问题就可以,在父组件中定义了一个数组对象,然后遍历它,把当前对象(site)传给子组件属性(site)。

通过setter截听输入属性值的变化

使用输入属性的 setter 方法来拦截父组件中值的变化,并做相应处理。

parent.component.ts
import { Component } from '@angular/core';

@Component({
    selector: 'parent-component',
    template: `<child-component *ngFor="let site of parentSites" [site]="site"></child-component>`
})
export class ParentComponent {
    title = "parent";
    parentSites: any = [
        {
            name: "云库网",
            domain: "http://yunkus.com"
        },
        {
            name: "朝夕熊博客",
            domain: "http://zhaoxixiong.com"
        }
    ];
}
child.component.ts
import { Component, Input } from '@angular/core';

@Component({
    selector: 'child-component',
    template: `
    <div>
        <h3>{{childSite.name}}</h3>
        <p>{{childSite.domain}}</p>
    </div>
    `
})

export class ChildComponent {
    childSite: any;
    @Input()
    set site(site: any) {
        site.name = site.name + "--- change";
        site.domain = site.domain + "--- change";
        this.childSite = site;
    }
    get site(): any {
        return this.childSite;
    }
}

通过ngOnChanges()来截听输入属性值的变化

使用OnChanges 生命周期钩子接口的 ngOnChanges() 方法来监测输入属性值的变化并做出回应。

当需要监视多个、交互式输入属性的时候,本方法比用属性的 setter 更合适。

parent.component.ts
import { Component } from '@angular/core';

@Component({
    selector: 'parent-component',
    template: `
    <div>
        <label>姓名:</label>
        <input name="myName" value="{{myName}}" [(ngModel)]="myName" type="text">
    </div>
    <div>
        <label>年龄:</label>
        <input number name="myAge" value="{{myAge}}" [(ngModel)]="myAge" type="text">
    </div>
    <child-component [myName]="myName" [myAge]="myAge"></child-component>
    `
})
export class ParentComponent {
    myName: string = "云库网";
    myAge: number = 18;
}
child.component.ts
import { Component, Input, OnChanges, SimpleChange } from '@angular/core';

@Component({
    selector: 'child-component',
    template: ``
})

export class ChildComponent implements OnChanges {
    @Input() myName: string;
    @Input() myAge: number;

    ngOnChanges(changes: { [propKey: string]: SimpleChange }) {
        console.log(changes);
    }
}

此时,你就可以在ngOnChanges 方法中对得到的值进行相应的处理了。

在这里有一点需要注意的,那就是如果页面中有使用到到 ngModel 的双向绑定,那么你一定要记得在根模块中引入:

import { FormsModule } from '@angular/forms';

并且在在根模块的 imports 中添加它

......
  imports: [
    BrowserModule,
    FormsModule
  ],
......

如果不添加的话程序会报错:

报错

Can’t bind to ‘ngModel’ since it isn’t a known property of ‘input’

setter 截听和 ngOnChanges() 截听相当于对输入型绑定的一个增强,让你可以对父组件修改过来的值进行处理。

父组件监听子组件的事件

parent.component.ts
import { Component } from '@angular/core';

@Component({
    selector: 'parent-component',
    template: `
    <child-component [buttonName]="buttonName" (triggerEventEmitter)="trigger($event)"></child-component>
    `
})
export class ParentComponent {
    buttonName: string = "云库网专用按钮";
    trigger(params: string): void {
        console.log(params);
    }
}
child.component.ts
import { Component, Input, Output, EventEmitter } from '@angular/core';

@Component({
    selector: 'child-component',
    template: `<div><button (click)="fly()">{{buttonName}}</button></div>`
})

export class ChildComponent {
    @Input() buttonName: string;
    @Output() triggerEventEmitter = new EventEmitter<string>();
    fly(): void {
        this.triggerEventEmitter.emit("触发了我!");
    }
}

emit() 方法传扩的字符串参数,父组件可以在对应的方法中传一个 $event 就可以拿到它的值了。

父组件与子组件通过本地变量互动

parent.component.ts
import { Component } from '@angular/core';

@Component({
    selector: 'parent-component',
    template: `
    <button (click)="child.growUp()">点我执行子组件方法</button>
    <child-component #child></child-component>
    `
})
export class ParentComponent { }
child.component.ts
import { Component } from '@angular/core';

@Component({
    selector: 'child-component',
    template: `<div>我今年:{{age}}</div>`
})

export class ChildComponent {
    age: number = 18;
    growUp() {
        this.age++
    }
}

我们可以像上面那样通过本地变量实现父组件获取和调用子组件的属性和方法。

父组件调用@ViewChild()

parent.component.ts
import { Component, AfterViewInit, ViewChild } from '@angular/core';
import { ChildComponent } from './child.component';

@Component({
    selector: 'parent-component',
    template: `
    <button (click)="parentGrowUp()">点我执行方法</button>{{_ChildComponent.age}}
    <child-component></child-component>
    `
})
export class ParentComponent {

    // 拿到子组件实例的引用
    @ViewChild(ChildComponent)
    private _ChildComponent: ChildComponent;

    ngAfterViewInit() {
        // 修改子组件中的 age 属性值
        this._ChildComponent.age = 20;
    }

    parentGrowUp() {
        this._ChildComponent.growUp();
    }
}
child.component.ts
import { Component } from '@angular/core';

@Component({
    selector: 'child-component',
    template: `<div>我今年:{{age}}</div>`
})

export class ChildComponent {
    age: number = 18;
    growUp() {
        this.age++
    }
}

通过@ViewChild属性装饰器,将子组件 child.component 注入到私有属性 _ChildComponent 里面。这个其实就相当于本地变量,只不过本地变量在模板中使用,而通过@ViewChild属性装饰器可以让你在类中方便地使用子组件的相关属性和方法。

这里有一个地方需要注意的,那就是在父组件中修改子组件的 age 属性时,如果是在开发环境中是会报错的:

报错

ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: ’18’. Current value: ’20’.

要想不报错那就得切换到生产环境。修改 environment.ts 文件:

export const environment = {
  production: true
};

改成 true 就可以了。

父组件和子组件通过服务来通讯

parent.component.ts
import { Component, OnInit } from '@angular/core';
import { Person } from './person';
import { PersonService } from './person.service';
import { ChildComponent } from './child.component';

@Component({
    selector: 'parent-component',
    template: `
    <button (click)="parentGrowUp()">时间飞逝</button>
    <div>
        <p>老爸今年:{{person?.age+18}}</p>
    </div>
    <hr>
    <child-component></child-component>
    `,
    providers: [PersonService]
})
export class ParentComponent implements OnInit {
    person: Person;
    constructor(private _personService: PersonService) { }

    ngOnInit(): void {
        this.getData();
    }
    getData(): void {
        this._personService.getPerson().then(data => {
            this.person = data[0];
        });
    }
    parentGrowUp() {
        this.person.age++;
    }
}
child.component.ts
import { Component, OnInit } from '@angular/core';
import { Person } from './person';
import { PersonService } from './person.service';
@Component({
    selector: 'child-component',
    template: `
    <div>儿子我今年也是:{{person?.age}}</div>
    <p><button (click)="childGrowUp()">儿子要长大</button></p>
    `
})

export class ChildComponent implements OnInit {
    person: Person;
    constructor(private _personService: PersonService) { }
    ngOnInit(): void {
        this.getData();
    }
    getData(): void {
        this._personService.getPerson().then(data => {
            this.person = data[0];
        });
    }
    childGrowUp() {
        this.person.age++;
    }
}

模拟请求服务返回数据

person.service.ts
import { Injectable } from '@angular/core';
import { Person } from './person';
import { PERSON } from './person-mock';

@Injectable()
export class PersonService {
    getPerson(): Promise<Person[]> {
        return Promise.resolve(PERSON);
    }
}

模拟数据

person-mock.ts
import { Person } from './person';
export const PERSON: Person[] = [
  { id: "1", age: 18, name: "小明", sex: "男", phone: "15889879211", email: "123121@163. com", qq: "111110171" }
];

自定义一个 Person 类

person.ts
export class Person {
  id: string;
  name: string;
  sex: string;
  age: number;
  phone: string;
  email: string;
  qq: string;
}

这个示例是直接把服务引入到了父组件中,子组件和父组件就可以共用同一个服务实例,除了在父组件中引入服务外,我们还可以在根模块中引入服务,也是同样的步骤。如果在根模块中引入了服务,那么父组件就不需要再引入了。

  • 微信扫一扫,赏我

  • 支付宝扫一扫,赏我

声明

原创文章,不经本站同意,不得以任何形式转载,如有不便,请多多包涵!

本文永久链接:http://yunkus.com/angular-core-knowledge-component-interaction/

发表评论

电子邮件地址不会被公开。 必填项已用*标注

评论 END