You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular 12中仅当ng-content非空时显示按钮的实现方案

解决方案

方案1:通过@ContentChildren检测投影列表项,控制按钮隐藏

Angular中ng-content的投影内容属于父组件,@ViewChild无法可靠获取这类元素,改用@ContentChildren专门监听投影元素,能彻底避免nativeElement undefined的问题,同时满足你不能在按钮上用*ngIf的要求。

组件代码

import { Component, ContentChildren, ElementRef, QueryList } from '@angular/core';

@Component({
  selector: 'app-dropdown',
  template: `
    <!-- 用[hidden]替代*ngIf实现隐藏 -->
    <button [hidden]="!hasValidListItems">打开下拉</button>
    <div class="dropdown-container">
      <ng-content></ng-content>
    </div>
  `
})
export class DropdownComponent {
  // 查询所有投影进来的元素,包含后代元素(适配<li>嵌套在<ul>的场景)
  @ContentChildren(ElementRef, { descendants: true }) private listItems!: QueryList<ElementRef<HTMLLIElement>>;

  // 计算属性判断是否存在有效<li>项
  get hasValidListItems(): boolean {
    if (!this.listItems) return false;
    // 过滤出真正的<li>元素,排除其他无关标签
    return this.listItems.filter(item => item.nativeElement.tagName === 'LI').length > 0;
  }
}

父组件使用示例

<app-dropdown>
  <!-- 带*ngIf的动态列表项也能被准确检测 -->
  <li *ngIf="showOptions">选项1</li>
  <li *ngIf="showOptions">选项2</li>
</app-dropdown>

方案2:子组件自身控制显示(仅当有有效列表项时渲染组件)

如果允许从子组件角度处理,直接在内部判断投影内容,决定是否渲染整个组件:

子组件代码

import { Component, ContentChildren, ElementRef, QueryList, AfterContentInit } from '@angular/core';

@Component({
  selector: 'app-dropdown',
  template: `
    <ng-container *ngIf="isVisible">
      <button>打开下拉</button>
      <div class="dropdown-container">
        <ng-content></ng-content>
      </div>
    </ng-container>
  `
})
export class DropdownComponent implements AfterContentInit {
  isVisible = false;
  @ContentChildren(ElementRef, { descendants: true }) private listItems!: QueryList<ElementRef<HTMLLIElement>>;

  ngAfterContentInit(): void {
    // 初始检测列表项状态
    this.updateVisibility();
    // 监听列表项动态变化(比如父组件中*ngIf切换时)
    this.listItems.changes.subscribe(() => this.updateVisibility());
  }

  private updateVisibility(): void {
    const validItems = this.listItems?.filter(item => item.nativeElement.tagName === 'LI');
    this.isVisible = validItems?.length > 0;
  }
}

为什么之前的@ViewChild方案会报错?

@ViewChild只能查询当前组件模板内定义的元素,而ng-content的内容是父组件投影进来的,不属于当前组件的模板树,所以在ngAfterViewInit中可能还未完成投影,或者根本无法获取到目标元素,最终导致nativeElement undefined。@ContentChildren是Angular专门为投影内容设计的查询方式,会自动跟踪投影内容的添加/移除,可靠性更高。

内容的提问来源于stack exchange,提问作者rbrtj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 02:35:33