美文网首页
Angular 内容投影

Angular 内容投影

作者: Messix_1102 | 来源:发表于2022-12-13 09:10 被阅读0次

    Angular 内容投影实际上就是在组件设置一个占位符,引用组件的时候可以拿自定义元素替代占位符以实现灵活自定义。

    1. 单槽投影

    • 创建一个组件, 在组件模板中,添加 <ng-content> 元素。
      import { Component } from '@angular/core';
      
      @Component({
        selector: 'app-zippy-basic',
        template: `
        <h2>Single-slot content projection</h2>
        <ng-content></ng-content>
        `
      })
      export class ZippyBasicComponent {}
      
    • 使用组建的地方可以自定义插槽内容
      <app-zippy-basic>
        <p>Is content projection cool?</p>
      </app-zippy-basic>
      

    2. 多槽投影

    • 多槽投影顾名思义: 一个组件可以接收多个插槽,这意味着接收的多个元素要与多个插槽需要有一一对应关系,这个对应关系可以通过选择器来实现。
    • 创建组件,在模板中添加具有选择器的 <ng-content> 元素
      import { Component } from '@angular/core';
      
      @Component({
        selector: 'app-zippy-multislot',
        template: `
        <div style="border: 1px solid;">
          <!-- 多插槽 -->
          <!-- 可以使用html 标签,css class,自定义组件名称,自定义属性名称来锁定投影位置 -->
          <ng-content select="h3"></ng-content>
          <ng-content select=".my-class"></ng-content>
          <ng-content select="app-my-hello"></ng-content>
          <ng-content select="[content]"></ng-content>
        </div>
        <div style="border: 1px solid;">
            <!-- 投影子元素 -->
            <!-- 使用ng-container来包裹子元素,减少不必要的dom层,类似vue中的template -->
            <ng-content select="question"></ng-content>
        </div>
        `
      })
      export class ZippyMultislotComponent {}
      
    • 使用选择器属性来一一匹配传入元素
      <app-zippy-multislot>
        <h3>使用标签锁定投影位置</h3>
        <div class="my-class">使用class锁定投影位置</div>
        <app-my-hello>使用自定义组件名称锁定投影位置</app-my-hello>
        <div content>使用自定义属性锁定投影位置</div>
        <ng-container ngProjectAs="question">
            <p>内容投影酷吗?</p>
            <p>内容投影酷吗?</p>
            <p>内容投影酷吗?</p>
            <p>内容投影酷吗?</p>
        </ng-container>
      </app-zippy-multislot>
      

    3. 有条件的投影

    • 首先定义两个指令
      // ContentDirective 用于获取 templateRef 操作元素内容
      import { Directive, TemplateRef } from '@angular/core';
      
      @Directive({
        selector: '[appContent]',
      })
      export class ContentDirective {
        constructor(public templateRef: TemplateRef<unknown>) {}
      }
      
      // ToggleDirective 获取元素点击事件, 操作容器元素属性
      import { Directive, HostListener } from '@angular/core';
      import { ContainerTestComponent } from './container-test.component';
      
      @Directive({
        selector: '[appToggle]',
      })
      export class ToggleDirective {
        @HostListener('click') toggle() {
          this.app.expanded = !this.app.expanded;
        }
        constructor(public app: ContainerTestComponent) {}
      }
      
    • 定义包含 ng-container 容器组件: container-test。容器组件使用了 之前定义的 ContentDirective 指令
      <!-- component template -->
      <div style="border: 1px solid;">
          <ng-content select="[button]"></ng-content>
          <p *ngIf="expanded">
            <ng-container [ngTemplateOutlet]="content.templateRef"> </ng-container>
          </p>
      </div>
      
      // component ts script
      import { Component, OnInit, ContentChild } from '@angular/core';
      import { ContentDirective } from './content.directive';
      
      @Component({
        selector: 'app-container-test',
        templateUrl: './container-test.component.html',
        styleUrls: ['./container-test.component.css']
      })
      export class ContainerTestComponent implements OnInit {
        expanded: boolean = false;
        @ContentChild(ContentDirective) content!: ContentDirective;
      
        constructor() { }
      
        ngOnInit(): void {
        }
      
      }
      
    • 由 slot-test 组件调用容器组件,slot 用到了之前定义的 appToggle 组件,点击切换按钮,组件内会隐藏/显示 组件 app-my-hello 的内容
      <!-- component template -->
      <app-container-test>
        <div button>
            <button appToggle>切换</button>
        </div>
        <ng-template appContent>
            <app-my-hello>有条件的内容投影~</app-my-hello>
        </ng-template>
      </app-container-test>
      
      // component ts script
      import { Component, OnInit } from '@angular/core';
      
      @Component({
        selector: 'app-slot-test',
        templateUrl: './slot-test.component.html',
        styleUrls: ['./slot-test.component.css']
      })
      export class SlotTestComponent implements OnInit {
        constructor() { }
        ngOnInit(): void {
        }
      }
      

    相关文章

      网友评论

          本文标题:Angular 内容投影

          本文链接:https://www.haomeiwen.com/subject/ltdcqdtx.html