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

为何无法用*ngIf条件隐藏cdkDropList?有无解决方案?

解决Angular CDK DropList因条件隐藏导致的引用报错问题

问题场景

在Angular项目中使用CDK拖拽组件,有两个cdkDropList:

  • #weisen:需要通过组件TS中isFirstRound()函数的返回值条件隐藏,添加*ngIf="isFirstRound()"后编译报错
  • #playerThreeHand:其cdkDropListConnectedTo属性中直接引用了weisen模板变量

报错信息:

Error: src/app/game/game.component.html:83:50 - error TS2551: Property 'weisen' does not exist on type 'GameComponent'.

83         [cdkDropListConnectedTo]="[cardsOnTable, weisen]"
                                                    ~~~~~~

  src/app/game/game.component.ts:9:16
    9   templateUrl: './game.component.html',
                     ~~~~~~~~~~~~~~~~~~~~~~~
    Error occurs in the template of component GameComponent.

核心原因:*ngIf会在条件不满足时销毁DOM元素,导致weisen模板变量不存在,但playerThreeHand仍在尝试引用它。


解决方案

方案1:用[hidden]替代*ngIf

*ngIf会销毁DOM,而[hidden]仅通过CSS隐藏元素,模板变量始终存在,无需修改其他逻辑:

<div
    cdkDropList
    #weisen="cdkDropList"
    [cdkDropListData]="weisenList"
    [cdkDropListConnectedTo]="[playerThreeHand]"
    class="horizontal weisen"
    [hidden]="!isFirstRound()" <!-- 替换原*ngIf -->
    cdkDropListOrientation="horizontal"
    (cdkDropListDropped)="drop($event)">
    <div *ngFor="let card of weisenList">
        <img class="horizontal_card" src="assets/french_cards/{{card.cardID}}.svg" cdkDrag>
    </div>
</div>

方案2:TS中动态生成连接列表

在组件TS中定义计算属性,根据条件动态控制是否包含weisen:

  1. 先在TS中获取模板引用:
import { CdkDropList, ViewChild } from '@angular/cdk/drag-drop';

@Component({/* 组件原有配置 */})
export class GameComponent {
  @ViewChild('weisen') weisen?: CdkDropList;
  @ViewChild('cardsOnTable') cardsOnTable!: CdkDropList;

  get connectedPlayerThreeLists() {
    const baseLists = [this.cardsOnTable];
    // 条件满足时才添加weisen
    if (this.isFirstRound() && this.weisen) {
      baseLists.push(this.weisen);
    }
    return baseLists;
  }

  isFirstRound(): boolean {
    // 你的条件判断逻辑
    return true;
  }
}
  1. 修改playerThreeHand的连接配置:
<div
    cdkDropList
    #playerThreeHand="cdkDropList"
    [cdkDropListData]="playerThreeHandList"
    [cdkDropListConnectedTo]="connectedPlayerThreeLists" <!-- 替换原数组 -->
    class="horizontal bottom"
    cdkDropListOrientation="horizontal"
    (cdkDropListDropped)="drop($event)">
    <div *ngFor="let card of playerThreeHandList">
        <img class="horizontal_card" src="assets/french_cards/{{card.cardID}}.svg" cdkDrag>
    </div>
</div>

方案3:使用模板变量可选链(Angular 12+)

直接在模板中用可选链语法,当weisen不存在时自动忽略该元素:

<div
    cdkDropList
    #playerThreeHand="cdkDropList"
    [cdkDropListData]="playerThreeHandList"
    [cdkDropListConnectedTo]="[cardsOnTable, weisen?]" <!-- 添加?可选链 -->
    class="horizontal bottom"
    cdkDropListOrientation="horizontal"
    (cdkDropListDropped)="drop($event)">
    <div *ngFor="let card of playerThreeHandList">
        <img class="horizontal_card" src="assets/french_cards/{{card.cardID}}.svg" cdkDrag>
    </div>
</div>

方案对比

  • 方案1:实现最简单,无需修改TS代码,适合仅需隐藏、不需要销毁组件的场景。
  • 方案2:逻辑灵活可控,适合复杂条件判断或需要精确管理连接关系的场景。
  • 方案3:语法最简洁,要求Angular版本≥12,适合新项目或已完成版本升级的项目。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 01:50:24