如何用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">×</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>
实现说明
- 拖拽逻辑:通过监听
mousedown(在模态框头部)、mousemove和mouseup事件,计算鼠标移动的偏移量,动态修改模态框的top和left样式来实现拖拽。 - 初始位置:通过
@Input()属性initialTop和initialLeft可以给每个模态框设置不同的初始位置,避免打开时重叠。 - 样式调整:把
.modal-dialog的定位设为fixed,移除默认的居中margin,确保拖拽时相对于视口移动,同时修改鼠标样式为move提示可拖拽。
现在你可以测试一下:点击按钮1打开模态框1,拖拽它到任意位置,然后点击按钮2打开模态框2,同样可以拖拽,两个模态框会同时显示且互不影响。
内容的提问来源于stack exchange,提问作者Mukul Sharma
相关产品推荐
相关产品推荐

