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

Angular 17指令隐藏div后innerHTML丢失问题求助

Angular 17 自定义指令导致元素内容丢失的解决办法

使用Angular 17结合Tailwind CSS开发时,自定义指令原本要实现:根据复选框的选中/取消状态,给标记的<div>添加或移除hidden类。但运行后发现目标<div>的innerHTML被清空,切换display样式为block/none也没解决问题。

问题代码

指令代码

import {
  Directive,
  ElementRef,
  Input,
  HostListener,
  Renderer2,
} from '@angular/core';

@Directive({
  selector: '[checkBoxAccordionTrigger]',
  standalone: true,
})
export class CheckBoxAccordionDirective {
  @Input('checkBoxAccordionTrigger') triggerId!: any;

  constructor(private el: ElementRef, private renderer: Renderer2) {}

  @HostListener('change') onChange() {
    const accordionBodyElement = this.renderer.selectRootElement(
      `[accordion-body=&quot;${this.triggerId}&quot;]`
    );

    if (this.el.nativeElement.checked) {
      // this.renderer.removeClass(accordionBodyElement, 'hidden');
      this.renderer.removeStyle(accordionBodyElement, 'display');
    } else {
      // this.renderer.addClass(accordionBodyElement, 'hidden');
      this.renderer.setStyle(accordionBodyElement, 'display', 'hidden');
    }
  }
}

HTML代码

<div id="demands" class="mb-6 items-center">
    <div *ngFor="let departmentDemand of departmentDemandList; let i = index">
        <div class="mb-6 items-center">
            <p class="w-5/12 mr-4 font-semibold underline">{{i+1}} - {{departmentDemand.DepartmentName }} :</p>
        </div>

        <div class="mb-6" *ngFor="let demand of departmentDemand.Demands">
            <div class="flex items-center">
                <input type="checkbox" name="{{ demand.Name }}" value="{{ demand.Name }}" class="mr-2"
                    checkBoxAccordionTrigger="{{demand.Id}}">
                <label for="{{ demand.Id }}">{{ demand.Name }}</label>
            </div>

            <div class="mt-6 ml-8 " [attr.accordion-body]="demand.Id">
                <div *ngFor="let parameter of demand.Parameters" class="mb-2 items-center flex">
                    <label [for]="parameter.Id" class="w-3/12 block mr-4">{{ parameter.Name }} :</label>
                    <input [id]="parameter.Id" [name]="parameter.Name"
                        class="w-7/12 px-3 py-2 border rounded-md focus:outline-none focus:border-blue-200">
                </div>
            </div>

        </div>
    </div>
</div>

问题原因

核心问题出在Renderer2.selectRootElement方法的调用上:该方法默认会清空目标元素的内容(第二个参数preserveContent默认是false),导致你选中的[accordion-body]元素innerHTML被移除。另外,display: hidden是无效的CSS值,正确的隐藏应该用display: none。

解决办法

  1. 修改selectRootElement调用,添加第二个参数true以保留元素内容;
  2. 换回Tailwind的hidden类来控制显示隐藏(更符合Tailwind的使用习惯),或者正确设置display: none。

修改后的指令代码:

import {
  Directive,
  ElementRef,
  Input,
  HostListener,
  Renderer2,
} from '@angular/core';

@Directive({
  selector: '[checkBoxAccordionTrigger]',
  standalone: true,
})
export class CheckBoxAccordionDirective {
  @Input('checkBoxAccordionTrigger') triggerId!: any;

  constructor(private el: ElementRef, private renderer: Renderer2) {}

  @HostListener('change') onChange() {
    // 添加第二个参数true,保留元素原有内容
    const accordionBodyElement = this.renderer.selectRootElement(
      `[accordion-body="${this.triggerId}"]`,
      true
    );

    if (this.el.nativeElement.checked) {
      this.renderer.removeClass(accordionBodyElement, 'hidden');
      // 如果用样式控制:this.renderer.removeStyle(accordionBodyElement, 'display');
    } else {
      this.renderer.addClass(accordionBodyElement, 'hidden');
      // 如果用样式控制:this.renderer.setStyle(accordionBodyElement, 'display', 'none');
    }
  }
}

另外,建议在HTML中使用属性绑定替代插值,让代码更规范:

<input type="checkbox" [name]="demand.Name" [value]="demand.Name" class="mr-2"
       checkBoxAccordionTrigger="{{demand.Id}}">

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 07:22:53