Angular(7) 学习资料 (2)组件

组件

组件控制屏幕上被称为视图的一小片区域。当用户在应用中穿行时,Angular 就会创建、更新、销毁一些组件。 你的应用可以通过一些可选的生命周期钩子(比如ngOnInit())来在每个特定的时机采取行动。

@Component 装饰器会指出紧随其后的那个类是个组件类,并为其指定元数据。组件的元数据告诉 Angular 到哪里获取它需要的主要构造块,以创建和展示这个组件及其视图。

@Component({
  // CSS 选择器,在其他视图中使用 <app-hero-list></app-hero-list> 引入对应组件
  selector:    'app-hero-list',
  // templateUrl 对应模板的地址
  // template 对应的模板字符串
  templateUrl: './hero-list.component.html',
  // 注入的服务
  providers:  [ HeroService ]
})
export class HeroListComponent implements OnInit, OnChanges, OnDestroy { }

生命周期(按照执行顺序排列)

  • ngOnChanges() : 当 Angular(重新)设置数据绑定输入属性时响应。 该方法接受当前和上一属性值的 SimpleChanges 对象。在 ngOnInit() 之前以及所绑定的一个或多个输入属性的值发生变化时都会调用。
  • ngOnInit() : 在 Angular 第一次显示数据绑定和设置指令/组件的输入属性之后,初始化指令/组件。在第一轮 ngOnChanges() 完成之后调用,只调用一次。
  • ngDoCheck() : 检测,并在发生 Angular 无法或不愿意自己检测的变化时作出反应。在每个变更检测周期中,紧跟在 ngOnChanges() 和 ngOnInit() 后面调用。
  • ngAfterContentInit() : 没当 Angular 把外部内容投影进组件/指令的视图之后调用。第一次 ngDoCheck() 之后调用,只调用一次。
  • ngAfterContentChecked() : 每当 Angular 完成被投影组件内容的变更检测之后调用。ngAfterContentInit() 和每次 ngDoCheck() 之后调用
  • ngAfterViewInit() : 每当 Angular 初始化完组件视图及其子视图之后调用。第一次 ngAfterContentChecked() 之后调用,只调用一次。
  • ngAfterViewChecked() : 每当 Angular 做完组件视图和子视图的变更检测之后调用。ngAfterViewInit() 和每次 ngAfterContentChecked() 之后调用。
  • ngOnDestroy() : 没当 Angular 每次销毁指令/组件之前调用并清扫。 在这儿反订阅可观察对象和分离事件处理器,以防内存泄漏。在 Angular 销毁指令/组件之前调用。

父子组件的执行顺序:

  • 开始,顺序调用父子组件的构造函数
  • 父类加载到 ngAfterContentChecked 生命周期
  • 子类完全加载完毕
  • 父类加载完毕
  • 父类发生变化 ngDoCheck ngAfterContentChecked
  • 子类变化并更新完毕 ngDoCheck ngAfterContentChecked ngAfterViewChecked
  • 父类更新完毕 ngAfterViewChecked
  • 子类注销完毕 ngOnDestroy
  • 父类注销完毕 ngOnDestroy

模板语法

绑定的类型可以根据数据流的方向分成三类: 从数据源到视图从视图到数据源以及双向的从视图到数据源再到视图

<!-- 从数据源到视图  -->
<span>{{ message }}</span>
<span>{{ num * 2 + list.length }}</span>
<span title="{{ title }}"></span>
<span [title]="title"></span>
<span bind-title="title"></span>

<!-- 从视图到数据源 -->
<button (click)="onClick($event)"></button>
<button on-click="onClick($event)"></button>

<!-- 双向的从视图到数据源再到视图 -->
<input [(value)]="value">
<input bindon-value="value">

注意:使用双向绑定需要在对应模块导入 FormsModule 模块

组件交互

子级接受父级的数据

  • 子组件通过 @Input 接受父级传入的数据
  • 子级通过 ngOnChanges 来监听父级数据的变化
  • 通过服务来共享数据

父级接受子级的数据

  • 通过监听的方式 EventEmitter.emit
  • 通过本地变量
  • 父组件调用@ViewChild()
  • 通过服务来共享数据
// 父组件
import { Component, OnInit } from '@angular/core'

@Component({
  selector: 'app-parent',
  template: `
    <input [(ngModel)]="parentInput" />
    <input [(ngModel)]="childernInput" />
    <app-children [parentInput]="parentInput" (childrenValue)="childrenValueFn($event)"></app-children>
  `,
  styleUrls: ['./parent.component.less']
})
export class ParentComponent implements OnInit {
  // 父组件的输入
  parentInput: string
  // 子组件的输入
  childernInput: string

  constructor() {}

  ngOnInit() {}

  // 接受子组件的数据
  childrenValueFn(event: string) {
    this.childernInput = event
  }
}


// 子组件
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'

@Component({
  selector: 'app-children',
  template: `
    <input type="text" [(ngModel)]="childernInput" (ngModelChange)="inputChange($event)" />
    <input type="text" [(ngModel)]="parentInput" />
  `,
  styleUrls: ['./children.component.less']
})
export class ChildrenComponent implements OnInit {
  // 子组件的输入
  childernInput: string

  // 接受父子间传入的数据
  @Input() parentInput: string

  @Output() childrenValue = new EventEmitter<string>()

  constructor() {}

  ngOnInit() {}

  inputChange(event) {
    // 向父组件传递数据
    this.childrenValue.emit(event)
  }
}


// 父组件使用本地变量
import { Component, OnInit } from '@angular/core'

@Component({
  selector: 'app-parent',
  template: `
    {{ children.xxx }}
    <app-children #children></app-children>
  `,
  styleUrls: ['./parent.component.less']
})
export class ChildrenComponent implements OnInit {}



// 父组件调用 @ViewChild()
import { Component, AfterViewInit, ViewChild } from '@angular/core'
import { ChildrenComponent } from './childern/children.component'

@Component({
  selector: 'app-parent',
  template: `<app-children></app-children>`,
  styleUrls: ['./parent.component.less']
})
export class ParentComponent implements AfterViewInit {

  @ViewChild(ChildrenComponent)
  private children: ChildrenComponent;

  constructor() {}

  ngAfterViewInit() {
    this.children.xxx
  }
}

动态组件

  • 创建一个组件用来动态加载组件
  • 组件内部引入一个指令用来拿到具体容器视图的访问权
// 指令
import { Directive, ViewContainerRef } from '@angular/core';
@Directive({
  selector: '[get-view]'
})
export class GetView {
  constructor(public viewContainerRef: ViewContainerRef) { }
}

// 动态加载组件
@Component({
  selector: 'dynamic-component',
  template: `
    <div>我要动态加载组件</div>
    <!-- 具体组件存放的地址 -->
    <ng-template get-view></ng-template>
  `
})
export class DynamicComponent implements OnInit {
  @Input() conponent: any;
  @ViewChild(GetView) view: GetView;
  constructor(private cfr: ComponentFactoryResolver) { }

  ngOnInit() {
    this.loadComponent();
  }

  loadComponent() {
    if(conponent) {
      let cf = this.cfr.resolveComponentFactory(conponent);
      let view = this.view.viewContainerRef;
      view.clear();
      let componentRef = view.createComponent(cf);
      componentRef.instance.data = view.data;
    }
  }
}

// 其他使用
export class AppComponent {
  constructor(component: OtherComponent) { }
}

`<dynamic-component [component]="component"></dynamic-component>`
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值