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

如何用ngx-bootstrap实现同一页面多个可拖拽非嵌套模态框?

实现ngx-bootstrap多可拖拽非嵌套模态框

嘿,你已经迈出了很棒的一步!你的现有代码已经能实现多个模态框同时显示了,现在只需要给模态框加上拖拽功能就能达成目标。下面是完整的修改方案:

第一步:确认多模态框同时显示的配置

你已经在模态框的config里设置了backdrop: false和ignoreBackdropClick: true,这确保了打开多个模态框时不会互相干扰,点击背景也不会关闭它们,这部分是完全正确的。另外你通过不同的@ViewChild引用不同的模态框组件,也保证了它们的独立性。

第二步:给模态框添加拖拽功能

ngx-bootstrap的Modal组件本身没有内置拖拽功能,我们可以通过Angular的事件监听来实现简单的拖拽逻辑:

修改modal-dailog.component.ts

添加拖拽相关的变量、DOM引用和事件处理方法:

import {Component, Input, ViewChild, ElementRef, HostListener} from '@angular/core';
import { ModalDirective } from 'ngx-bootstrap';

@Component({
 selector: 'common-modal',
 templateUrl: './modal-dailog.component.html',
 styles: [`
   .modal-dialog {
     position: fixed;
     cursor: move;
     margin: 0;
   }
   .modal-header {
     cursor: move;
   }
 `]
})
export class CommonModalComponent {
 @ViewChild('childModal') public childModal: ModalDirective;
 @ViewChild('modalDialog') public modalDialog: ElementRef;
 @Input() title?: string;
 @Input() initialTop = '20%';
 @Input() initialLeft = '30%';

 private isDragging = false;
 private dragStartX: number;
 private dragStartY: number;
 private initialModalTop: number;
 private initialModalLeft: number;

 constructor() { }

 ngAfterViewInit() {
   // 设置初始位置
   if (this.modalDialog.nativeElement) {
     this.modalDialog.nativeElement.style.top = this.initialTop;
     this.modalDialog.nativeElement.style.left = this.initialLeft;
   }
 }

 show() {
   this.childModal.show();
 }

 hide() {
   this.childModal.hide();
 }

 startDrag(event: MouseEvent) {
   this.isDragging = true;
   // 记录鼠标初始位置和模态框当前位置
   this.dragStartX = event.clientX;
   this.dragStartY = event.clientY;
   const modalStyle = window.getComputedStyle(this.modalDialog.nativeElement);
   this.initialModalTop = parseInt(modalStyle.top, 10);
   this.initialModalLeft = parseInt(modalStyle.left, 10);

   // 阻止事件冒泡,避免触发其他元素的事件
   event.preventDefault();
 }

 @HostListener('document:mousemove', ['$event'])
 onMouseMove(event: MouseEvent) {
   if (!this.isDragging) return;

   // 计算鼠标移动的偏移量
   const deltaX = event.clientX - this.dragStartX;
   const deltaY = event.clientY - this.dragStartY;

   // 更新模态框的位置
   this.modalDialog.nativeElement.style.top = `${this.initialModalTop + deltaY}px`;
   this.modalDialog.nativeElement.style.left = `${this.initialModalLeft + deltaX}px`;
 }

 @HostListener('document:mouseup')
 onMouseUp() {
   this.isDragging = false;
 }
}

修改modal-dailog.component.html

添加模态框DOM的引用,并给modal-header绑定拖拽开始事件:

<div id='wrapper'>
 <div bsModal #childModal="bs-modal" class="modal fade" role="dialog" aria-labelledby="mySmallModalLabel" [config]="{backdrop: false, ignoreBackdropClick: true}" aria-hidden="false">
 <!-- 添加#modalDialog引用,移除默认居中的margin类 -->
 <div #modalDialog class="modal-dialog">
 <div class="modal-content">
 <div class="modal-header" (mousedown)="startDrag($event)">
 <h4 class="modal-title pull-left">{{title}}</h4>
 <button type="button" class="close pull-right" aria-label="Close" (click)="hide()">
 <span aria-hidden="true">&times;</span>
 </button>
 </div>
 <div class="modal-body">
 <ng-content select=".modal-body">
 </ng-content>
 </div>
 <div class="modal-footer">
 <ng-content select=".modal-footer">
 </ng-content>
 </div>
 </div>
 </div>
 </div>
</div>

修改parent.component.html

给每个模态框设置不同的初始位置,避免打开时重叠:

<button type="button" class="btn btn-primary" (click)="childModal.show()">打开模态框1</button>
<common-modal #childModal [title]="'模态框1'" [initialTop]="'15%'" [initialLeft]="'20%'">
 <div class="modal-body">
 你好,这是模态框1的内容
 </div>
 <div class="modal-footer">
 <button type="button" class="btn btn-primary" (click)="onCancle()" >关闭</button>
 </div>
</common-modal>

<button type="button" class="btn btn-primary" (click)="childModal2.show()">打开模态框2</button>
<common-modal #childModal2 [title]="'模态框2'" [initialTop]="'35%'" [initialLeft]="'50%'">
 <div class="modal-body">
 你好,这是模态框2的内容
 </div>
 <div class="modal-footer">
 <button type="button" class="btn btn-primary" (click)="onCancle2()" >关闭</button>
 </div>
</common-modal>

实现说明

  1. 拖拽逻辑:通过监听mousedown(在模态框头部)、mousemove和mouseup事件,计算鼠标移动的偏移量,动态修改模态框的top和left样式来实现拖拽。
  2. 初始位置:通过@Input()属性initialTop和initialLeft可以给每个模态框设置不同的初始位置,避免打开时重叠。
  3. 样式调整:把.modal-dialog的定位设为fixed,移除默认的居中margin,确保拖拽时相对于视口移动,同时修改鼠标样式为move提示可拖拽。

现在你可以测试一下:点击按钮1打开模态框1,拖拽它到任意位置,然后点击按钮2打开模态框2,同样可以拖拽,两个模态框会同时显示且互不影响。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:16:46