Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Angular 2 组件之间如何通信? #23

Open
Coohack opened this issue Jan 16, 2016 · 12 comments
Open

Angular 2 组件之间如何通信? #23

Coohack opened this issue Jan 16, 2016 · 12 comments

Comments

@Coohack
Copy link

Coohack commented Jan 16, 2016

想要在组件之间共享数据,还有互相调用方法。依赖注入是单例的吗

@kittencup kittencup changed the title 组件之间如何通信? Angular 2 组件之间如何通信? Jan 16, 2016
@kittencup
Copy link
Owner

组件之间的共享可以有好几种方式

父->子 input 方式

import {Component,Input} from 'angular2/core';
@Component({
    selector: 'child',
    template: `
        <h2>child {{content}}</h2>
    `
})
class Child {
    @Input() content:string;
}

@Component({
    selector: 'App',
    directives: [Child],
    template: `
        <h1>App</h1>
        <child [content]="i"></child>
    `
})
export class App {

    i:number = 0;

    constructor() {
        setInterval(()=> {
            this.i++;
        }, 1000)
    }

}

子->父 output 方式

import {Output,EventEmitter,Component} from 'angular2/core';

@Component({
    selector: 'child',
    template: `
        <h2>child</h2>
    `
})
class Child {
    @Output() updateNumberI:EventEmitter<number> = new EventEmitter();
    i:number = 0;

    constructor() {
        setInterval(()=> {
            this.updateNumberI.emit(++this.i);
        }, 1000)
    }
}

@Component({
    selector: 'App',
    directives: [Child],
    template: `
        <h1>App {{i}}</h1>
        <child (updateNumberI)="numberIChange($event)"></child>
    `
})
export class App {

    i:number = 0;

    numberIChange(i:number){
        this.i = i;
    }

}

子获得父实例

如果不了解forwardRef用处的的可以看 #11
@Host 表示这个Injector必须是host element在这里可以理解为 parent

import {Host,Component,forwardRef} from 'angular2/core';

@Component({
    selector: 'child',
    template: `
        <h2>child</h2>
    `
})
class Child {

    constructor(@Host() @Inject(forwardRef(()=> App)) app:App) {
        setInterval(()=> {
            app.i++;
        }, 1000);
    }
}

@Component({
    selector: 'App',
    directives: [Child],
    template: `
        <h1>App {{i}}</h1>
        <child></child>
    `
})
export class App {
    i:number = 0;
}

父获得子实例

子元素指令在父constructor时是获取不到的,所以必须在组件的ngAfterViewInit生命周期钩子后才能获取,如果对组件生命周期不了解的话,可以参考 #56

import {ViewChild,Component} from 'angular2/core';

@Component({
    selector: 'child',
    template: `
        <h2>child {{i}}</h2>
    `
})
class Child {
    i:number = 0;
}

@Component({
    selector: 'App',
    directives: [Child],
    template: `
        <h1>App {{i}}</h1>
        <child></child>
    `
})
export class App {

    @ViewChild(Child) child:Child;
    ngAfterViewInit() {
        setInterval(()=> {
            this.child.i++;
        }, 1000)
    }

}

service 方式

import {Component,Injectable} from 'angular2/core';

@Injectable();
class KittencupService {
    i:number = 0;
}

@Component({
    selector: 'child',
    template: `
        <h2>child {{service.i}}</h2>
    `
})
class Child {

    constructor(public service:KittencupService){

    }
}

@Component({
    selector: 'App',
    directives: [Child],
    providers: [KittencupService],
    template: `
        <h1>App {{i}}</h1>
        <child></child>
    `
})
export class App {

    constructor(service:KittencupService) {
        setInterval(()=> {
            service.i++;
        }, 1000)
    }

}

service EventEmitter方式

import {Component,Injectable,EventEmitter} from 'angular2/core';

@Injectable()
class KittencupService {
    change: EventEmitter<number>;

    constructor(){
        this.change = new EventEmitter();
    }
}

@Component({
    selector: 'child',
    template: `
<h2>child {{i}}</h2>
`
})
class Child {

    public i:number = 0;

    constructor(public service:KittencupService){

        service.change.subscribe((value:number)=>{
            this.i = value;
        })
    }
}

@Component({
    selector: 'App',
    directives: [Child],
    providers: [KittencupService],
    template: `
<h1>App {{i}}</h1>
<child></child>
`
})
export class App {

    i:number = 0;

    constructor(service:KittencupService) {
        setInterval(()=> {
            service.change.emit(++this.i);
        }, 1000)
    }

}

@hstarorg
Copy link

service并不是单例,兄弟组件之间又该如何通信呢?

@hstarorg
Copy link

把服务放在最外层的根组件上,内部全部使用它,就变相的成了单例。

@hstarorg
Copy link

另外,请教下,如下做法是否可取。暂时还没有考虑取消订阅:

import {EventEmitter, Injectable} from 'angular2/core';

@Injectable()
export class EventBus {
  private callback: EventEmitter<any>;
  private subscriberObj: any;
  public constructor() {
    this.callback = new EventEmitter();
    this.subscriberObj = {};
  }

  public on(eventName, cb) {
    if (!this.subscriberObj.hasOwnProperty(eventName)) {
      this.subscriberObj[eventName] = [];
    }
    this.subscriberObj[eventName].push(cb);
    this.callback.subscribe((eventObj) => {
      if (this.subscriberObj.hasOwnProperty(eventObj.eventName)) {
        for (let fn of this.subscriberObj[eventObj.eventName]) {
          fn.apply(null, [eventObj.data]);
        }
      }
    });
  }

  public emit(eventName, data) {
    this.callback.emit({ eventName: eventName, data: data });
  }
}

@pengkobe
Copy link

话说哪几种方式比较好呢,或者适应的场景是什么?敬请大神回答,不慎感激

@freyhill
Copy link

freyhill commented Sep 6, 2017

很赞

@oyboyb
Copy link

oyboyb commented Dec 7, 2017

兄弟组件是用什么通信呢?

@jiayisheji
Copy link

借助公共父级,服务,ngrx

@oyboyb
Copy link

oyboyb commented Dec 7, 2017

看来也只能这样了,但你那个ngrx是什么鬼,没有理解到位

@jiayisheji
Copy link

ng专用状态管理,自行百度谷歌

@oyboyb
Copy link

oyboyb commented Dec 7, 2017

3q

@fattypiggy
Copy link

@oyboyb 我觉得很好地一种方式就是同一父级引用各个兄弟的实例,然后每个子组建通知父组件,然后父组件再去通知子组件的兄弟, 就像 @jiayisheji 所说的公共父级, ngrx目前没有研究过,等研究一番后再来补充答案。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants