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="${this.triggerId}"]` ); 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。
解决办法
- 修改
selectRootElement调用,添加第二个参数true以保留元素内容; - 换回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
相关产品推荐
相关产品推荐

