Maison  >  Article  >  interface Web  >  Un article pour comprendre les trois types de projection de contenu dans Angular (single slot, multi-slot, conditionnelle)

Un article pour comprendre les trois types de projection de contenu dans Angular (single slot, multi-slot, conditionnelle)

青灯夜游
青灯夜游avant
2021-10-14 10:42:303246parcourir

Cet article vous guidera à travers la projection de contenu dans angular et présentera la projection de contenu à emplacement unique, la projection de contenu à emplacements multiples et la projection de contenu conditionnel. J'espère qu'il sera utile à tout le monde !

Un article pour comprendre les trois types de projection de contenu dans Angular (single slot, multi-slot, conditionnelle)

【Recommandation de didacticiel connexe : "tutoriel angulaire"】

Projection de contenu à emplacement unique

La projection de contenu à emplacement unique signifie créer un composant dans lequel vous pouvez projeter un composant.

zippy-basic.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-zippy-basic',
  template: `
  <h2>单插槽内容投影</h2>
  <ng-content></ng-content>
`
})
export class ZippyBasicComponent {}

Avec l'élément ng-content, les utilisateurs de ce composant peuvent désormais projeter leurs propres messages dans le composant. Par exemple : ng-content 元素,该组件的用户现在可以将自己的消息投影到该组件中。例如:

app.component.html

<!-- 将 app-zippy-basic 元素包裹的全部内容投影到 zippy-basic 组件中去 -->
<app-zippy-basic>
  <p>单插槽内容投影:投影数据</p>
</app-zippy-basic>

效果如下:
Un article pour comprendre les trois types de projection de contenu dans Angular (single slot, multi-slot, conditionnelle)

ng-content 元素是一个占位符,它不会创建真正的 DOM 元素。ng-content 的那些自定义属性将被忽略。

多插槽内容投影

  • 组件模板含有多个ng-content标签。
  • 为了区分投影的内容可以投影到对应ng-content标签,需要使用ng-content标签上的select属性作为识别。
  • select属性支持标签名、属性、CSS 类和 :not 伪类的任意组合。
  • 不添加select属性的ng-content标签将作为默认插槽。所有为匹配的投影内容都会投影在该ng-content的位置。

zippy-multislot.component.ts

import { Component } from &#39;@angular/core&#39;;

@Component({
  selector: &#39;app-zippy-multislot&#39;,
  template: `
  <h2>多插槽内容投影</h2>
  <ng-content></ng-content>
  <ng-content select="[question]"></ng-content>
`
})
export class ZippyMultislotComponent {}

app.component.html

<!-- 使用 question 属性的内容将投影到带有 `select=[question]` 属性的 ng-content 元素。 -->
<app-zippy-multislot>
  <p question style="color: hotpink;">
    带question属性的p元素
  </p>
  <p style="color: lightgreen">不带question属性的p元素-->匹配到不带select属性的ng-content</p>
  <p>不带question属性的p元素-->匹配到不带select属性的ng-content</p>
</app-zippy-multislot>

效果如下:
Un article pour comprendre les trois types de projection de contenu dans Angular (single slot, multi-slot, conditionnelle)

在前面的示例中,只有第二个 ng-content 元素定义了select 属性。结果,第一个 ng-content 元素就会接收投影到组件中的任何其他内容。

有条件的内容投影

推荐使用ng-container标签,因为该标签不需要渲染真实的 DOM 元素。

<ng-container *ngTemplateOutlet="templateRefExp; context: contextExp"></ng-container>
<!-- 等同 -->
<ng-container [ngTemplateOutlet]="templateRefExp" [ngTemplateOutletContext]="contextExp"></ng-container>
参数 类型 说明
templateRefExp TemplateRef | null 一个字符串,用于定义模板引用以及模板的上下文对象
contextExp Object | null 是一个对象,该对象的键名将可以在局部模板中使用 let 声明中进行绑定。在上下文对象中使用 $implicit 为键名时,将把它作为默认值。

ng-template 标签的#ID会匹配templateRefExp,将ng-template标签的内容嵌入到指定的ngTemplateOutlet中。

例一:

<header>头部</header>
<main>
	<h3>内容:</h3>
	<ng-container [ngTemplateOutlet]="greet"></ng-container>
</main>
<footer>底部</footer>

<ng-template #greet>
	<div>
		<h4>hi!</h4>
		<h4>hello my dear friend!</h4>
	</div>
</ng-template>

效果:

Un article pour comprendre les trois types de projection de contenu dans Angular (single slot, multi-slot, conditionnelle)

ViewChild和ContentChild

  • ContentChild:与内容子节点有关,操作投影进来的内容;
  • ViewChild:与视图子节点有关,操作自身的视图内容;

ContentChild

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

首先创建两个组件

/**** part-b.component.ts ****/
import { Component, OnInit,Output} from &#39;@angular/core&#39;;

@Component({
	selector: &#39;app-content-part-b&#39;,
	templateUrl: &#39;./part-b.component.html&#39;,
	styleUrls: [&#39;./part-b.component.scss&#39;]
})

export class PartBComponent implements OnInit {
	constructor() { }
	ngOnInit() { }
	
	public func():void{
		console.log("PartB");
	} 
}
/**** part-a.component.ts ****/
import { Component, OnInit, ContentChild } from &#39;@angular/core&#39;;
// 1、引入 part-b 组件
import { PartBComponent } from &#39;../part-b/part-b.component&#39;;

@Component({
	selector: &#39;app-content-part-a&#39;,
	templateUrl: &#39;./part-a.component.html&#39;,
	styleUrls: [&#39;./part-a.component.scss&#39;]
})

export class PartAComponent implements OnInit {
	// 2、获取投影
	@ContentChild(PartBComponent) PartB:PartBComponent
	constructor() { }
	ngOnInit() {}
	ngAfterContentInit(): void {
		// 3、调用 part-b 组件的 func() 方法
		this.PartB.func();
	}
	public func() {
		console.log(&#39;PartA&#39;)
	}
}

part-b组件的内容投影到part-a组件中

 <!-- content.component.html -->
<div>
	<div>Content</div>
	<div>
		<app-content-part-a>
		<!-- 投影在part-a组件中的内容 -->
			<h1>PartA--start</h1>
			<app-content-part-b></app-content-part-b>
			<span>PartA--end</span>
		</app-content-part-a>
	</div>
</div>

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

ViewChild

上一部分的ContentChild操作的时投影进来的内容,而ViewChild操作的是自身的视图内容
给上一部分的content.component.html修改如下:

 <!-- content.component.html -->
<div>
	<div>Content</div>
	<div>
	<!-- 在此处引用模板变量 #partA -->
		<app-content-part-a #partA>
			<h1>PartA--start</h1>
				<app-content-part-b></app-content-part-b>
			<span>PartA--end</span>
		</app-content-part-a>
	</div>
</div>
/**** content.component.ts ****/
import { Component, OnInit, ViewChild } from &#39;@angular/core&#39;;

@Component({
	selector: &#39;app-content&#39;,
	templateUrl: &#39;./content.component.html&#39;,
	styleUrls: [&#39;./content.component.scss&#39;]
})

export class ContentComponent implements OnInit {
	// 2、获取视图 partA
	@ViewChild(&#39;partA&#39;) partA: any;
	constructor() { }
	ngOnInit() {}
	ngAfterViewInit(): void {
		// 3、调用 part-a 组件的 func() 方法
		this.partA.func();
	}
}

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

ContentChildViewChild还存在复数的形式,即ContentChildrenViewChildren

app.component.html

import { Component, OnInit, ContentChild,ContentChildren ,QueryList } from &#39;@angular/core&#39;;
import { PartBComponent } from &#39;../part-b/part-b.component&#39;;

@Component({
	selector: &#39;app-content-part-a&#39;,
	templateUrl: &#39;./part-a.component.html&#39;,
	styleUrls: [&#39;./part-a.component.scss&#39;]
})
export class PartAComponent implements OnInit {

	@ContentChildren(PartBComponent) PartBs: QueryList<PartBComponent>;

	constructor() { }
	ngOnInit() {}
}

L'effet est le suivant :
Insérer la description de l'image ici

L'élément ng-content est un espace réservé, il ne crée pas un véritable élément DOM. Ces attributs personnalisés de ng-content seront ignorés.

🎜🎜🎜Projection de contenu multi-slot🎜🎜🎜
  • Le modèle de composant contient plusieurs balises ng-content.
  • Afin de distinguer le contenu projeté qui peut être projeté sur la balise ng-content correspondante, vous devez utiliser selectsur le ng -content tag >Attribut comme identification.
  • L'attribut select prend en charge toute combinaison de noms de balises, d'attributs, de classes CSS et de pseudo-classes :not.
  • La balise ng-content sans ajouter l'attribut select sera utilisée comme emplacement par défaut. Tout le contenu projeté correspondant sera projeté à la position du contenu ng.
🎜🎜zippy-multislot.component.ts🎜rrreee🎜app.component.html🎜rrreee🎜L'effet est le suivant :
Insérer la description de l'image ici🎜🎜🎜Dans l'exemple précédent, seul le deuxième élément ng-content a l'attribut select défini. En conséquence, le premier élément ng-content recevra tout autre contenu projeté dans le composant. 🎜🎜🎜🎜🎜Projection de contenu conditionnel🎜🎜🎜🎜 Il est recommandé d'utiliser la balise ng-container car cette balise ne nécessite pas de rendu d'éléments DOM réels. 🎜🎜rrreee
Paramètre Type Description
templateRefExp TemplateRef | null Une chaîne utilisée pour définir la référence du modèle et l'objet contextuel du modèle
contextExp Object | null est un objet dont le nom de clé peut être lié dans une instruction let dans un modèle local. Lorsque vous utilisez $implicit comme nom de clé dans un objet contextuel, il sera utilisé comme valeur par défaut.
🎜Le #ID de la balise ng-template correspondra à templateRefExp, et le le contenu de la balise ng-template est intégré dans le ngTemplateOutlet spécifié. 🎜🎜Exemple 1 : 🎜rrreee🎜Effet : 🎜🎜Insérer une image ici Description 🎜🎜🎜ViewChild et ContentChild🎜🎜
  • ContentChild : lié au sous-nœud de contenu, 🎜opère le contenu projeté🎜;
  • ViewChild : lié au nœud vue enfant, 🎜exploite son propre contenu de vue🎜 ;

🎜ContentChild🎜

🎜Dans la partie précédente, nous avons utilisé la projection de contenu pour permettre aux balises de composants personnalisés d'intégrer des balises html ou des balises de composants personnalisées, alors comment cela fonctionne-t-il sur le contenu projeté 🎜🎜Créez d'abord deux composants🎜rrreeerrreee🎜projetez le contenu du composant part-b ? au composant part-a 🎜rrreee🎜🎜Dans le cycle de vie du composant, il y a un hook ngAfterContentInit() qui est lié à l'initialisation du contenu projeté, nous nous préoccupons donc du contenu projeté Essayez d'effectuer l'opération une fois son initialisation terminée🎜🎜

🎜ViewChild🎜

🎜L'opération ContentChild dans la partie précédente est le contenu projeté, while ViewChild Ce qui fonctionne, c'est son propre contenu de vue
Modifiez le content.component.html de la partie précédente comme suit : 🎜rrreeerrreee🎜🎜ngAfterContentInit() correspond à <code> ngAfterViewInit() (l'initialisation du nœud de vue a lieu après l'initialisation du contenu projeté) 🎜🎜🎜ContentChild et ViewChild existent également dans au pluriel, c'est-à-dire ContentChildren et <code>ViewChildren, ils obtiennent une collection de nœuds, il n'y a pas de différence entre les autres 🎜🎜L'écriture est la suivante : 🎜rrreee🎜Pour pour plus de connaissances liées à la programmation, veuillez visiter : 🎜Introduction à la programmation🎜 ! ! 🎜

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer