CS 工作日志 - Generic Component 的 url 设置逻辑 - ngTemplateOutlet 和 ng-container 的配套使用

如果是 external url,走上面的模版,否则走下面 id 为 isLocalUrl 的模版。

external or local,通过正则表达式判断。http/https/mailto 就是 external.

<ng-container *ngTemplateOutlet="content"></ng-container>

在 Angular 开发中,<ng-container *ngTemplateOutlet="content"></ng-container> 是一个非常有用的模式,具备多种实际应用。它通过动态插入模板内容,增强了 Angular 组件的灵活性与动态性。下面会通过详细的解释和示例来剖析这段代码的用途和语法。

基本解释

<ng-container> 是 Angular 提供的虚拟元素,不会被渲染为实际的 DOM 元素。它本质上是一个占位符,可以在其中应用指令和绑定数据,而不影响 DOM 结构。与标准的 <div><span> 标签不同,它不会生成多余的 HTML 元素,从而有助于保持 DOM 的简洁性。

*ngTemplateOutlet 指令允许我们动态插入 ng-template 的内容。所谓 “ng-template” 是一种 Angular 提供的模板块,可以在需要时被动态创建并插入到视图中。结合 <ng-container> 一起使用,*ngTemplateOutlet 可以引用一个模板,并在该位置插入其内容。

下面是这段代码的具体分解:

<ng-container *ngTemplateOutlet="content"></ng-container>
  1. <ng-container>:虚拟元素,不会出现在实际的 DOM 中。
  2. *ngTemplateOutlet:结构性指令,用于插入模板。
  3. content:指向要插入的模板,可以是组件中的模板变量。

应用场景

这种模式适用于多种场景,如动态内容展示、多分支逻辑、复用模板等。以下通过实际示例深入说明其具体用途。

简单示例:动态内容展示

假设有一个组件,用于展示用户状态信息,有多个不同的状态。我们希望根据状态动态插入相应的模板内容。

首先定义两个 ng-template,分别对应不同的用户状态:

<!-- app.component.html -->
<ng-template #activeTemplate>
  <p>用户当前处于活跃状态</p>
</ng-template>

<ng-template #inactiveTemplate>
  <p>用户当前处于非活跃状态</p>
</ng-template>

<!-- 插入动态内容 -->
<ng-container *ngTemplateOutlet="currentTemplate"></ng-container>

在组件类中定义逻辑,决定哪个模板被插入:

// app.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  userStatus: string = 'active';  // 假设状态来自某个服务或逻辑

  // 根据状态选择模板
  get currentTemplate() {
    return this.userStatus === 'active' ? this.activeTemplate : this.inactiveTemplate;
  }

  // Angular 会自动填充此属性
  @ViewChild('activeTemplate', { static: true }) activeTemplate!: TemplateRef<any>;
  @ViewChild('inactiveTemplate', { static: true }) inactiveTemplate!: TemplateRef<any>;
}

通过这种方式,我们可以根据 userStatus 动态插入相应的模板,避免了冗长的 ngIf 判断。

复杂示例:表单动态布局

动态表单是另一个常见的应用场景。如果有一个表单,其中部分字段根据用户选择的选项动态变化,可以使用 *ngTemplateOutlet 来实现。

定义多个 ng-template,每个模板对应一种表单布局:

<!-- app.component.html -->
<form>
  <label for="selection">选择布局:</label>
  <select id="selection" (change)="onSelectionChange($event.target.value)">
    <option value="layout1">布局1</option>
    <option value="layout2">布局2</option>
  </select>

  <ng-container *ngTemplateOutlet="currentLayout"></ng-container>
</form>

<ng-template #layout1>
  <label for="field1">字段1:</label>
  <input id="field1" type="text">
  <br>
  <label for="field2">字段2:</label>
  <input id="field2" type="text">
</ng-template>

<ng-template #layout2>
  <label for="field3">字段3:</label>
  <input id="field3" type="text">
  <br>
  <label for="field4">字段4:</label>
  <input id="field4" type="text">
</ng-template>

在组件类中实现切换逻辑:

// app.component.ts
import { Component, ViewChild, TemplateRef } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  @ViewChild('layout1', { static: true }) layout1!: TemplateRef<any>;
  @ViewChild('layout2', { static: true }) layout2!: TemplateRef<any>;
  currentLayout!: TemplateRef<any>;

  constructor() {
    this.currentLayout = this.layout1;  // 默认布局
  }

  onSelectionChange(selection: string) {
    this.currentLayout = selection === 'layout1' ? this.layout1 : this.layout2;
  }
}

这种方式不仅提高了代码的可读性和维护性,还使得界面更加灵活,易于调整。

高级应用:复用组件和模板

在大型应用中,复用组件和模板是非常重要的。通过 *ngTemplateOutlet,可以实现模板的复用,将常见的 UI 片段封装为 ng-template,在不同的场景中动态插入。

定义一个共享的 ng-template

<!-- shared.templates.html-->
<ng-template #sharedTemplate let-item>
  <div class="item-card">
    <h3>{{ item.title }}</h3>
    <p>{{ item.description }}</p>
  </div>
</ng-template>

在组件中复用这个模板:

<!-- item-list.component.html -->
<ng-container *ngFor="let item of items">
  <ng-container *ngTemplateOutlet="sharedTemplate; context: { $implicit: item }"></ng-container>
</ng-container>
// item-list.component.ts
import { Component, ViewChild, TemplateRef } from '@angular/core';

@Component({
  selector: 'app-item-list',
  templateUrl: './item-list.component.html',
  styleUrls: ['./item-list.component.css']
})
export class ItemListComponent {
  @ViewChild('sharedTemplate', { static: true }) sharedTemplate!: TemplateRef<any>;
  items = [
    { title: 'Item 1', description: 'Description 1' },
    { title: 'Item 2', description: 'Description 2' }
  ];
}

通过上述方法,可以高效地复用模板,避免重复代码,提高开发效率。

总结与优势

通过 *ngTemplateOutlet<ng-container> 的结合使用,可以实现:

  1. 动态内容展示:根据不同的条件动态插入相应的模板内容,避免了冗长的 ngIf 判断。
  2. 多样化布局:可根据用户选择动态调整表单或界面布局,增强用户体验。
  3. 模板复用:将常见的 UI 片段封装为模板,便于在多个组件中复用,提高开发效率和代码一致性。
  4. 代码简洁<ng-container> 本身不会生成实际 DOM 元素,保持了 DOM 的简洁性。

这种灵活的模板插入机制,使得 Angular 组件可以更高效地响应不同的需求与变化,为现代前端开发提供了强有力的支持。通过合理应用,可以显著提升应用程序的灵活性与维护性。

  • 21
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值