美文网首页
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