ng-content @ContentChild @ContentChildren学习

本文介绍了如何在Angular中实现自定义标签的嵌套,并详细解释了如何利用ng-content指令和ContentChild装饰器来实现内容的精准定位和元素的获取。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考博客:https://segmentfault.com/a/1190000008707828

我们在写HTML时经常使用到标签嵌套,比如:

<div>
    <p>嵌套</p>
</div>

在angular自定义标签里面能否实现标签的嵌套呢?答案是肯定的.

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

@Component({
    selector: 'exe-greet',
    template: `
    <div class="border">
        <p>Greet Component</p>  
        <ng-content></ng-content>
    </div>
    `,
    styles: [` .border { border: 2px solid #eee; } `]
})
export class GreetComponent { }
/* parent.component.ts */
import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `
    <h4>Welcome to Angular World</h4>
    <exe-greet>
      <p>Hello Semlinker</p>
    </exe-greet>
  `,
})
export class AppComponent { }

效果如下:
image.png
在页面里即有child组件的内容,也有parent组件child子组件嵌套的内容,也就是说parent组件child子组件嵌套的内容
映射到了 ng-content 标签上了,将代码稍微改一下:

<exe-greet>
    <p>Hello Semlinker</p>
    <p>Hello Bob</p>
</exe-greet>

页面上的效果就变成这样了
image.png

如果需要下面的效果
image.png
可以写成这样

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

@Component({
  selector: 'my-app',
  template: `
    <h4>Welcome to Angular World</h4>
    <exe-greet>
      <div style="border: 1px solid #666; margin: 4px;">
         <div style="border: 1px solid red; margin: 5px;">Card Header</div>
         <div style="border: 1px solid green; margin: 5px;">Card Body</div>
         <div style="border: 1px solid blue; margin: 5px;">Card Footer</div>
      </div>
    </exe-greet>
  `,
})
export class AppComponent { }

虽然效果实现了,假设在另一个页面,也需要使用GreetComponent组件,那么还需要再次设置预设的样式.我们能不能把卡片风格的各个部分的默认样式定义在GreetComponent组件中,使用组件时我们只需关心自定内容区域的样式,当然也可以,调整后的代码

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

@Component({
    selector: 'exe-greet',
    template: `
    <div class="border">
        <p>Greet Component</p>  
        <div style="border: 1px solid #666;margin: 4px;">
            <div style="border: 1px solid red;margin: 5px;">
                <ng-content></ng-content>
            </div>
            <div style="border: 1px solid green;margin: 5px;">
                <ng-content></ng-content>
            </div>
            <div style="border: 1px solid blue;margin: 5px;">
                 <ng-content></ng-content>
            </div>
        </div>
    </div>
    `,
    styles: [` .border { border: 2px solid #eee; } `]
})
export class GreetComponent{ }

现在遇到的问题是怎样将父组件映射的内容与 ng-content 进行一一对应,好在 ng-content 支持 select 属性,它支持我们常用的选择器类型,如:

  • 标签选择器、
  • 类选择器、
  • ID选择器、
/*greet.component.ts*/
<div style="border: 1px solid #666;margin: 4px;">
     <div style="border: 1px solid red;margin: 5px;">
         <ng-content select="header"></ng-content>
     </div>
     <div style="border: 1px solid green;margin: 5px;">
         <ng-content select=".card_body"></ng-content>
     </div>
     <div style="border: 1px solid blue;margin: 5px;">
         <ng-content select="footer"></ng-content>
     </div>
</div>
/*parent.component.ts*/
import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `
    <h4>Welcome to Angular World</h4>
    <exe-greet>
      <header>Card Header</header>
          <div class="card_body">Card Body</div>
      <footer>Card Footer</footer>
    </exe-greet>
  `,
})
export class AppComponent { }

ContentChild
以前面的例子为例,我们在 AppComponent 组件中定义的内容,通过 ng-content 指令提供的选择器,成功投射到 GreetComponent 组件中。

但是我们只能让greet的元素显示,而不能获取到class中的属性,我想要class中的属性该怎么办呢?

了解完 Content Projection,接下来我们来介绍 ContentChild。

ContentChild 是属性装饰器,用来从通过 Content Projection 方式设置的视图中获取匹配的元素。

我们需要借助 @ContentChild 装饰器来处理

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

@Component({
    selector: 'exe-child',
    template: `
      <p>Child Component</p>  
    `
})
export class ChildComponent {
    name: string = 'child-component';
}
/*parent.component.ts*/
import { Component, ContentChild, AfterContentInit } from '@angular/core';
import { ChildComponent } from './child.component';

@Component({
    selector: 'exe-parent',
    template: `
      <p>Parent Component</p>  
      <ng-content></ng-content>
    `
})
export class ParentComponent implements AfterContentInit {
    @ContentChild(ChildComponent)
    childCmp: ChildComponent;

    ngAfterContentInit() {
        console.dir(this.childCmp);
    }
}
/*app.component.ts*/
import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `
    <h4>Welcome to Angular World</h4>
    <exe-parent>
      <exe-child></exe-child>
    </exe-parent>
  `,
})
export class AppComponent { }

ContentChildren 属性装饰器用来从通过 Content Projection 方式设置的视图中获取匹配的多个元素,返回的结果是一个 QueryList 集合。

/*parent.component.ts*/
import { Component, ContentChildren, QueryList, AfterContentInit } from '@angular/core';
import { ChildComponent } from './child.component';

@Component({
    selector: 'exe-parent',
    template: `
      <p>Parent Component</p>  
      <ng-content></ng-content>
    `
})
export class ParentComponent implements AfterContentInit {

    @ContentChildren(ChildComponent)
    childCmps: QueryList<ChildComponent>;

    ngAfterContentInit() {
        console.dir(this.childCmps);
    }
}
/*app.component.ts*/
import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `
    <h4>Welcome to Angular World</h4>
    <exe-parent>
      <exe-child></exe-child>
      <exe-child></exe-child>
    </exe-parent>
  `,
})
export class AppComponent { }
<think>好的,我现在需要帮助用户解决关于ng-zorro-antd@9.1.2版本中是否有替代nzLoading属性的问题。首先,我得回忆一下用户的历史对话。之前用户遇到了升级到ng-zorro-antd@10时Node.js版本过低的问题,现在他们在旧版本v9.1.2中询问替代nzLoading的属性。 首先,我应该确认nzLoading在v9中的情况。根据之前的经验,nzLoading可能是在后续版本中被弃用或替换的,比如在v10中可能用其他属性替代了。但用户现在使用的是v9.1.2,我需要检查该版本的文档或更新日志,确认nzLoading是否存在以及是否有替代方案。 接下来,用户可能因为某些原因无法升级到v10,所以需要找到在v9.1.2中可行的解决方案。我需要回忆或者查找ng-zorro-antd的版本历史,特别是v9的组件文档。例如,nzLoading通常用于按钮或空间加载状态,可能在v9中仍然有效,但可能有其他推荐的方法。 如果nzLoading在v9.1.2中仍然可用,用户可能误解了升级后的变化,需要澄清。但如果已被弃用,我需要找出替代属性。例如,在后续版本中,可能引入了nzSpin或者结合其他指令如NgIf或NgClass来手动控制加载状态。 另外,可能需要考虑用户的具体使用场景。比如,他们是否在按钮上使用nzLoading,还是在其他组件上。不同组件的加载状态处理方式可能不同。如果nzLoading在v9中确实没有直接替代属性,可能需要提供自定义实现的方案,比如使用CSS或结合其他组件。 还需要检查是否有官方迁移指南或版本更新说明,特别是从v9到v10的变化,看看是否有关于nzLoading的改动。例如,可能在v10中将nzLoading拆分为更细粒度的属性或改用其他组件。 此外,用户可能遇到升级困难,所以才继续使用v9,但需要确保他们的当前版本中能解决加载状态的问题。所以需要提供明确的替代方案,包括代码示例和步骤,确保他们能够顺利应用。 最后,总结信息,确保回答结构清晰,分点说明,并给出验证方法,帮助用户确认他们的组件版本,以及如何正确应用替代方案。</think>--- ### **问题定位** 在 `ng-zorro-antd@9.1.2` 版本中,`nzLoading` 是**按钮组件**(`<button nz-button>`)的核心属性,用于控制按钮的加载状态。但根据你的需求,可能存在以下两种情况: 1. **需要替换 `nzLoading` 的交互逻辑**(例如自定义加载状态)。 2. **组件版本兼容性问题**(例如误认为 `nzLoading` 被废弃)。 **关键结论**: - **在 `ng-zorro-antd@9.1.2` 中,`nzLoading` 仍是官方支持的属性,无需替代**。 - 如果你遇到该属性失效或需要自定义加载效果,需通过其他方式扩展功能。 --- ### **替代方案与扩展方法** --- #### **1. 直接使用 `nzLoading`(官方推荐)** **适用场景**:标准按钮加载状态控制。 **代码示例**: ```html <button nz-button [nzLoading]="isLoading" (click)="handleSubmit()">提交</button> ``` **属性说明**: | 属性 | 类型 | 作用 | |-------------|----------|-----------------------------| | `nzLoading` | `boolean`| 控制按钮是否显示加载图标和禁用状态。 | --- #### **2. 自定义加载状态(手动实现)** **适用场景**:需要更复杂的加载动画或与其他组件(如表单、卡片)结合。 **实现步骤**: 1. **通过 `[disabled]` 和图标控制按钮状态**: ```html <button nz-button [disabled]="isLoading" (click)="handleSubmit()"> <span *ngIf="!isLoading">提交</span> <span *ngIf="isLoading"> <i nz-icon nzType="loading"></i> 处理中... </span> </button> ``` 2. **结合全局加载指示器 `NzSpin`**: ```html <div nz-spin [nzSpinning]="isLoading"> <form>...</form> <button nz-button (click)="isLoading = true">提交</button> </div> ``` **优势**:覆盖整个区域的加载状态,避免用户误操作。 --- #### **3. 版本兼容性验证** **排查步骤**: 1. 确认项目中实际安装的 `ng-zorro-antd` 版本: ```bash npm list ng-zorro-antd # 输出应为 9.1.2 ``` 2. 检查 `nz-button` 的 API 文档: - 官方文档(v9):[NG-ZORRO 9.x Button](https://v9.ng.ant.design/components/button/zh) - 确认 `nzLoading` 属性存在且未被废弃。 --- ### **常见问题排查** 1. **`nzLoading` 不生效的可能原因**: - 未正确绑定布尔值:确保 `[nzLoading]="isLoading"` 中 `isLoading` 是 `boolean` 类型。 - 版本冲突:检查是否混用了不同版本的 NG-ZORRO(如部分组件升级到 v10)。 2. **升级到 v10+ 后的变化**: - 在 `ng-zorro-antd@10+` 中,`nzLoading` 仍保留,但推荐使用更细粒度的 `NzSpin` 或 `NzModal` 控制复杂场景。 --- ### **总结** - **在 `ng-zorro-antd@9.1.2` 中,`nzLoading` 是有效且推荐使用的属性**,无需替代。 - 若需要扩展功能,可通过以下方式: 1. 手动控制按钮状态(图标 + `disabled`)。 2. 使用 `NzSpin` 包裹组件实现区域加载。 3. 升级到 v10+ 后利用新版 API(需同步升级 Angular 和 Node.js)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值