Angular6 学习笔记——内容投影, ViewChild和ContentChild

angular6.x系列的学习笔记记录,仍在不断完善中,学习地址:

系列目录

(1)组件详解之模板语法

(2)组件详解之组件通讯

(3)内容投影, ViewChild和ContentChild

(4)指令

(5)路由

内容投影

1、为什么需要内容投影?
一个事物的出现,必然存在它所能解决的问题,让我们先从问题出发吧:
大家应该都知道,在html规范里面,它定义了非常多的标签,在这些标签里面,相同标签之间的嵌套,不同标签之间的嵌套,是十分常见,并且可行
同时,在Angular里面,我们可以通过自定义标签的方式引用组件,那么这里的标签能否像原生的html标签一样,来嵌入html标签,或者嵌套其他组件标签呢?
于是就引入我们今天的主要问题,用一个详细的例子来描述吧:
假设存在父组件Content,和它下面2个子组件PartA和PartB,自定义标签分别为:,,,目录结构如下

在这里插入图片描述

如果想在父组件的视图里面,完成下面的内容,是否可行呢?

content.component.html 

  <div>
    <div>Content</div>
    <div>
      <app-content-part-a>
        <h1>PartA--start</h1>
        <app-content-part-b></app-content-part-b>
        <span>PartA--end</span>
      </app-content-part-a>
    </div>
 </div>

这样是不行的,其结果只会显示自定义的组件自身的内容,因为自定义组件标签会忽略嵌套其中的html原生标签或者其他的自定义组件标签,从而使它们无法产生任何效果

2、如何使用内容投影?
上述问题通过内容投影则能够解决,那么如何使用内容投影呢?

只需要在组件PartA的视图里面做一些改动,内容如下

 part-a.component.html

<div>
      <div>
          <ng-content select="h1"></ng-content>
      </div>
      <div>
          <ng-content select="app-content-part-b"></ng-content>
      </div>
      <div>
          <ng-content select="span"></ng-content>
     </div>
 </div>

经过这样的修改,上述想要实现的效果就可以达到

那么内容投影是如何工作的呢?

首先通过angular里面的一个指令ng-content,实现占位,再通过select,达到选择器的作用,这样在组件生命周期过程,初始渲染投影内容的时候,就能够将对应的内容投影到特定的位置,这就是内容投影工作的简单描述

组件里面嵌套组件,之间的通讯问题可以参考组件间的通讯

ContentChild和ViewChild

首先做个简单的介绍:

ContentChild:与内容子节点有关,操作投影进来的内容;

ViewChild:与视图子节点有关,操作自身的视图内容;

在上一部分,我们通过内容投影,让自定义的组件标签能够嵌入html标签或自定义组件标签,那么它如何操作投影进来的内容呢?

还是以上述内容为例,从实际的问题出发:假设嵌入的自定义组件标签里面声明了一个方法func(),那么如何在里面去操作这个方法呢?
上面说过,ContentChild是操作投影进来的内容,那么在这里我们也可以通过它解决问题,在组件PartA内,通过ContentChild获取投影进来的组件PartB,并对它进行操作(部分代码在上一部分已经贴出,这一部分不予重复),代码如下

 part-b.component.ts

  import { Component, OnInit,Output} from '@angular/core';
  
  @Component({
    selector: 'app-content-part-b',
    templateUrl: './part-b.component.html',
    styleUrls: ['./part-b.component.scss']
  })
  export class PartBComponent implements OnInit {
    constructor() { }
 
   ngOnInit() {
   }
 
   public func():void{
    console.log("PartB");
   } 
 }
 part-a.component.ts

  import { Component, OnInit, ContentChild } from '@angular/core';
  import { PartBComponent } from '../part-b/part-b.component';
  
  @Component({
    selector: 'app-content-part-a',
    templateUrl: './part-a.component.html',
    styleUrls: ['./part-a.component.scss']
  })
  export class PartAComponent implements OnInit {
 
 @ContentChild(PartBComponent) PartB:PartBComponent
 
   constructor() { }
 
   ngOnInit() {}
 
   ngAfterContentInit(): void {
     this.PartB.func();
   }
 }

这里需要注意一点:在组件的生命周期里面,有一个钩子ngAfterContentInit()是与投影内容初始化有关,所以我们有关投影的内容操作尽量放在它初始化完成之后进行

如果理解了ContentChild的用法,那么ViewChild几乎没有理解难度,他们的差异不大,所不同的是:

1.ViewChild是操作视图本身存在的节点,而不是投影进来的内容

2.ngAfterContentInit()对应的是ngAfterViewInit()(视图节点初始化是在投影内容初始化之后)

其他没有什么不同,这里我就不再赘述

ContentChild和ViewChild还存在复数的形式,即ContentChildren和ViewChildren,它们取到的是节点的一个集合,其他的没有什么区别

写法如下:

  import { Component, OnInit, ContentChild,ContentChildren ,QueryList } from '@angular/core';
  import { PartBComponent } from '../part-b/part-b.component';
  
  @Component({
    selector: 'app-content-part-a',
    templateUrl: './part-a.component.html',
    styleUrls: ['./part-a.component.scss']
  })
  export class PartAComponent implements OnInit {
 
 @ContentChildren(PartBComponent)
 PartBs: QueryList<PartBComponent>;
 
   constructor() { }
 
   ngOnInit() {}
 
 }

上述代码中PartBs是组件PartB的一个集合,这就是复数的用法,ViewChildren不再赘述

(终)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值