Angular コンポーネントと対話する方法

php中世界最好的语言
リリース: 2018-06-14 10:06:24
オリジナル
1271 人が閲覧しました

今回は、Angular コンポーネントを使用して対話する方法と、Angular コンポーネントを使用して対話する際の注意点について説明します。以下は実際のケースです。見てみましょう。

親コンポーネントは子コンポーネントに渡します

子コンポーネントは @Input デコレータを通じて入力プロパティを定義し、親コンポーネントは子コンポーネントを参照するときにこれらの入力プロパティを通じて子コンポーネントにデータを渡します。子コンポーネントは、setter または ngOnChanges() を渡して、入力属性値の変更をインターセプトできます。

最初に 2 つのコンポーネント、つまりサブコンポーネント 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]=&#39;paramOneVal&#39; [paramTwo]=&#39;paramTwoVal&#39;></demo-child>
 `
})
export class DemoParentComponent {
 paramOneVal: any = '传递给paramOne的数据';
 paramTwoVal: any = '传递给paramTwo的数据';
}
ログイン後にコピー

親コンポーネントは、テンプレート内のセレクター demo-child を通じてサブコンポーネント DemoChildComponent を参照し、次の 2 つの入力プロパティ paramOne および paramTwo を通じてデータをサブコンポーネントに渡します。 paramOne に渡されるデータと paramTwo に渡されるデータは 2 行のテキストです。

セッターを介した入力属性値の変更のインターセプト

実際のアプリケーションでは、入力属性の値が変更されたときに対応する操作を実行する必要があることが多いため、この時点では入力のセッターを使用する必要があります属性。入力プロパティ値の変更をインターセプトします。

サブコンポーネント 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 に割り当てられていることがわかります。これにより、親コンポーネントが渡されます。データを子コンポーネントのエフェクトに渡します。もちろん、最も重要なことは、セッターでより多くの他の操作を実行できるようになり、プログラムがより柔軟になることです。

入力属性値の変更をインターセプトするには ngOnChanges() を使用します

複数の対話型入力属性を監視する必要がある場合、セッターを介して入力属性値の変更をインターセプトする方法では、単一の属性値の変更のみを監視できます。ある時点で、このアプローチは効果がなくなります。 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 メソッドによって受信されるパラメーターの変更は、入力属性名をキーとして、値を SimpleChange として持つオブジェクトです。SimpleChange オブジェクトには、現在の入力属性が変更されるかどうかが含まれます。初回および前回の値、現在の値、およびその他の属性。したがって、ngOnChanges メソッドでは、変更オブジェクトを走査することで複数の入力属性値を監視し、対応する操作を実行できます。

親コンポーネントのインスタンスを取得する

前述の説明では、子コンポーネントが @Input デコレータを通じて入力属性を定義するため、親コンポーネントは入力属性を通じて子コンポーネントにデータを渡すことができます。

もちろん、より積極的な方法を考えることもできます。それは、親コンポーネントのインスタンスを取得し、親コンポーネントの特定のプロパティまたはメソッドを呼び出して、必要なデータを取得することです。各コンポーネントのインスタンスがインジェクターのコンテナーに追加されることを考慮すると、依存関係の注入を通じて親コンポーネントのインスタンスを見つけることができます。

子コンポーネントが親コンポーネントのインスタンスを取得することは、親コンポーネントが子コンポーネントのインスタンスを取得すること(テンプレート変数、@ViewChild または @ViewChildren を通じて直接取得)よりも面倒です。

子コンポーネント内の親コンポーネントのインスタンスを取得するには、次の 2 つの状況があります:

親コンポーネントの型がわかっている

この場合、次のようにして、既知の型の親コンポーネントを直接取得できます。コンストラクター Quote に 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 のプロバイダー メタデータでエイリアス Provider を定義し、使用します。 useExisting を使用して親コンポーネント DemoParentComponent のインスタンスを挿入します。 コード例は次のとおりです。

@Component({
 selector: 'demo-parent',
 template: `
 <demo-child [paramOne]=&#39;paramOneVal&#39; [paramTwo]=&#39;paramTwoVal&#39;></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';
 }
}
ログイン後にコピー

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

css的新属性display:box使用方法

JS代码做出txt文件上传预览

以上がAngular コンポーネントと対話する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート