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

如何为ng-content中的元素添加cdkMenuItem指令?

解决方案:自动为内容投影元素添加cdkMenuItem

要给内容投影的元素自动添加cdkMenuItem,你不能直接在ngTemplateOutlet或ng-content上加指令——因为这些容器指令只会作用于自身,不会传递给投影的子元素。这里提供一种无需修改用户使用方式的可行实现:

方法:手动实例化CdkMenuItem指令

通过Angular的生命周期钩子和指令实例化API,在组件内部为每个投影元素自动创建并绑定CdkMenuItem指令。

修改table-col-actions.component.ts代码

import { CdkMenuItem, CdkMenu, CdkMenuModule, CDK_MENU } from '@angular/cdk/menu';
import { NgIf, NgTemplateOutlet, ContentChildren, ElementRef, QueryList, AfterContentInit, ViewChild } from '@angular/common';
import { ChangeDetectionStrategy, Component, Inject, Renderer2, Optional } from '@angular/core';
import { IconOptionsComponent } from '../../icons/icon-options.component';
import { DOCUMENT } from '@angular/common';

@Component({
    standalone: true,
    selector: 'table-col-actions',
    templateUrl: 'table-col-actions.component.html',
    changeDetection: ChangeDetectionStrategy.OnPush,
    imports: [NgIf, NgTemplateOutlet, IconOptionsComponent, CdkMenuModule],
})
export class TableColActionsComponent implements AfterContentInit {
  // 获取所有投影的直接子元素
  @ContentChildren(ElementRef, { descendants: false }) projectedElements!: QueryList<ElementRef>;
  // 获取组件内的cdkMenu实例
  @ViewChild(CdkMenu) menu!: CdkMenu;

  constructor(
    private injector: Injector,
    private renderer: Renderer2,
    @Inject(DOCUMENT) private document: Document,
    @Optional() @Inject(CDK_MENU) private parentMenu: CdkMenu | undefined,
  ) {}

  ngAfterContentInit(): void {
    this.projectedElements.forEach(elementRef => {
      const element = elementRef.nativeElement;
      // 添加cdk-menu-item默认样式(可选,CdkMenuItem内部也会自动添加)
      this.renderer.addClass(element, 'cdk-menu-item');
      
      // 创建CdkMenuItem实例并传入所需依赖
      const menuItem = new CdkMenuItem(
        elementRef,
        this.document,
        this.menu, // 将当前组件的菜单作为父菜单
        undefined,
        this.renderer,
        this.injector,
        undefined
      );

      // 手动触发指令的初始化逻辑
      menuItem.ngOnInit();
      // 将菜单项注册到父菜单中
      this.menu.addItem(menuItem);
    });
  }
}

原理说明

  1. 通过@ContentChildren获取所有投影到组件内的直接子元素;
  2. 在ngAfterContentInit钩子中,遍历每个元素并手动实例化CdkMenuItem指令;
  3. 将创建的菜单项注册到组件内的cdkMenu实例中,确保菜单逻辑正常工作。

这种方法完全保留了你原本的组件使用方式,无需用户额外修改投影内容的结构。

内容的提问来源于stack exchange,提问作者mandrag.ora

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 13:46:13