Angular模态框跳转搜索页面后遮罩层残留问题求助
解决Angular中Bootstrap模态框跳转后遮罩层残留问题
问题根源
当前代码在路由跳转前未主动关闭模态框,Bootstrap模态框的遮罩层(.modal-backdrop)是动态插入到<body>中的,Angular路由跳转时HomeComponent销毁,但遮罩层因属于body节点不会被自动清理,导致残留。同时混用jQuery和原生DOM事件绑定的方式,也会导致模态框状态控制不彻底。
修复方案
核心思路
- 改用Angular风格的模态框控制方式,避免原生DOM和jQuery操作
- 搜索提交时先关闭模态框,再执行路由跳转
- 组件销毁时强制清理残留的遮罩层和页面滚动限制
修改后的代码示例
TypeScript文件(home.component.ts)
import { Component, ElementRef, OnInit, OnDestroy, ViewChild } from '@angular/core'; import { Router } from '@angular/router'; import { Modal } from 'bootstrap'; @Component({ selector: 'app-home', templateUrl: './home.component.html', styleUrls: ['./home.component.css'], }) export class HomeComponent implements OnInit, OnDestroy { searchTerm: string = ''; private readonly imagesToShowInLandscape = ['bowl', 'paella', 'hotpot', 'omelette', 'brownChunks', 'tomYum', 'fish', 'raznjici', 'chickenThigh']; private readonly imagesToHideInPortrait = ['omelette', 'chickenThigh', 'tomYum']; @ViewChild('modal1') modal1!: ElementRef; @ViewChild('modal2') modal2!: ElementRef; private modal1Instance?: Modal; private modal2Instance?: Modal; constructor(private router: Router) {} ngOnInit() { // 初始化Bootstrap模态框实例 this.modal1Instance = new Modal(this.modal1.nativeElement); this.modal2Instance = new Modal(this.modal2.nativeElement); this.adjustImageVisibility(); window.addEventListener('resize', this.adjustImageVisibility); } ngOnDestroy() { window.removeEventListener('resize', this.adjustImageVisibility); // 销毁模态框实例,清理资源 this.modal1Instance?.dispose(); this.modal2Instance?.dispose(); // 强制清理残留遮罩层和页面滚动限制 this.cleanupModalBackdrops(); } search() { // 先关闭模态框,等待动画完成后跳转 this.modal1Instance?.hide(); setTimeout(() => { this.redirectToRecipes(this.searchTerm); }, 300); // 匹配Bootstrap模态框关闭动画时长 } searchModal2() { // 处理modal2的搜索逻辑 this.modal2Instance?.hide(); setTimeout(() => { const inputValue = this.modal2.nativeElement.querySelector('input').value; this.redirectToRecipes(inputValue); }, 300); } redirectToRecipes(searchTerm: string) { this.router.navigate(['/recipes'], { queryParams: { search: searchTerm } }); } openModal(target: 'modal1' | 'modal2') { // 统一的模态框打开方法 target === 'modal1' ? this.modal1Instance?.show() : this.modal2Instance?.show(); } adjustImageVisibility() { // 保留原有图片可见性调整逻辑 // ... 你的原有代码 } private cleanupModalBackdrops() { // 移除body中所有残留的遮罩层 document.querySelectorAll('.modal-backdrop').forEach(el => el.remove()); // 恢复页面滚动 document.body.classList.remove('modal-open'); } }
HTML文件(home.component.html)
<div class="row d-flex justify-content-center mt-5"> <!-- Kuham Button --> <div class="col-md-6 d-flex justify-content-center justify-content-md-end"> <div class="card bg-transparent border-0"> <div class="card-body d-flex justify-content-center" (click)="openModal('modal1')"> <a class="izberi"> <span class="button-text">Kuham</span> <img src="assets/images/cooking-icon.png" alt="Button Image" id="choice-images" /> </a> </div> </div> </div> <!-- Jem Button --> <div class="col-md-6 d-flex justify-content-center justify-content-md-start"> <div class="card bg-transparent border-0"> <div class="card-body d-flex justify-content-center" (click)="openModal('modal2')"> <a class="izberi"> <span class="button-text">Jem</span> <img src="assets/images/eating-icon2.png" alt="Button Image" id="choice-images" /> </a> </div> </div> </div> </div> <div class="modal" id="modal1" #modal1> <div class="modal-dialog modal-dialog-centered"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title">Kaj kuhaš?</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <form (ngSubmit)="search()"> <div class="mb-3"> <input class="form-control" type="text" [(ngModel)]="searchTerm" name="searchTerm" placeholder="Vpiši ime jedi ali sestavine"> </div> <button type="submit" class="btn btn-primary">Poišči</button> </form> </div> </div> </div> </div> <div class="modal" id="modal2" #modal2> <div class="modal-dialog modal-dialog-centered"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title">Kaj bi jedel?</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <form (ngSubmit)="searchModal2()"> <div class="mb-3"> <input class="form-control" type="text" placeholder="Vpiši ime jedi ali sestavine" aria-label="default input example"> </div> <button type="submit" class="btn btn-primary">Poišči</button> </form> </div> </div> </div> </div>
关键修改说明
- 移除原生DOM事件绑定和jQuery调用,改用
ViewChild和Bootstrap官方Modal类控制模态框,符合Angular组件化规范 - 搜索提交时先关闭模态框,等待动画完成后再跳转,确保遮罩层有时间被正常清理
- 组件销毁时强制清理残留遮罩层,并移除body上的
modal-open类,彻底恢复页面滚动和交互能力 - 统一模态框打开逻辑,简化代码结构
内容的提问来源于stack exchange,提问作者fatbigcat
相关产品推荐
相关产品推荐

