ngBootstrap Angular 8 - 模态可调整大小和可拖动
ngBootstrap Angular 8 - Modal Resizable and Draggable
我正在尝试将 bootstrap https://ng-bootstrap.github.io/#/components/modal/examples
版本 4 与 Angular 8 一起使用。我想让模态可调整大小并可拖动。我看到了一些其他版本的例子,比如 3.xx 但 angular - http://jsfiddle.net/GDVdN/
Bootstrap4 的任何参考 ANgular 8 - 模态可调整大小 + 可拖动?
我最接近的是创建一个组件,使内部的任何元素“可调整大小”。
更新:“玩”“modal-dialog”风格
想象一下这样的组件
<div class="resizable" [ngStyle]="style">
<ng-content></ng-content>
<div class="cell-border-top"></div>
<div class="cell-border-bottom"></div>
<div class="cell-border-left"></div>
<div class="cell-border-right"></div>
<div class="cell-top-right"></div>
<div class="cell-bottom-right"></div>
<div class="cell-top-left"></div>
<div class="cell-bottom-left"></div>
</div>
.css 使得divs 是左、右、上、下和四个角的位置
我们监听 mouseDown,并“获取”class我们可以将拖动类型存储在变量中的名称
export enum TypeDrag {
Move,
Top,
Bottom,
Left,
Right,
TopRight,
BottomRight,
TopLeft,
BottomLeft
}
当鼠标按下时,我们订阅 mouseUp 和 mouseMove,mouseUp 简单地删除对 mouseMove 的订阅
mouseMove改变样式div改变位置和尺寸
我们需要将 ElementRef 指定为 Input 以拖动“modal”
还有一个额外的考虑是 ngb-modal 将模态更改为“margin-left”和“margin-top”,所以我需要将 margin 设置为 0 到 a div 带有 calssName==“模态对话框”。为此,我们创建一个递归函数
为了获得“模态对话框”,我们使用递归函数
findModalContent(element:HTMLElement)
{
return element.className=="modal-dialog"?element:
element.parentElement?this.findModalContent(element.parentElement):
null
}
我尽量在代码中用注释来解释
通常这是 stackblitz
@Component({
selector: 'angular-window',
templateUrl: './angular-window.component.html',
styleUrls: ['./angular-window.component.css']
})
export class AngularWindowComponent implements OnInit {
rect: any;
incr: number[] = [0, 0, 0, 0];
nativeElement: any;
typeDrag: TypeDrag;
origin: any;
onDrag: boolean = false;
moveSubscription: any;
//div: any; <--remove in the updated
classNames = [
'cell-top',
'cell-border-top',
'cell-border-bottom',
'cell-border-left',
'cell-border-right',
'cell-top-right',
'cell-bottom-right',
'cell-top-left',
'cell-bottom-left'
];
style: any = null;
constructor(private elementRef: ElementRef) {}
@Input() set dragHolder(value) { //the drag holder will be a
//template reference variable
//we add the class "cell-top"
value.classList.add("cell-top");
}
/*It's not necesary now
//I need indicate the background-color
@Input('background-color') backgroundColor = 'white';
*/
ngOnInit(): void {
//get the "modalContent"
this.modalContent=this.findModalContent(this.elementRef.nativeElement)
//we subscribe to mouseDown
fromEvent(this.elementRef.nativeElement, 'mousedown')
.pipe(
//we filter, only get if the className of element
//is one of the indicate by the variable "classNames"
//or if the className include the "cell-top"
filter((event: MouseEvent) => {
const classs = (event.target as any).className;
if (classs && typeof classs === 'string') {
const className = classs.split(' ');
return className.indexOf("cell-top")>=0?true:
this.classNames.indexOf(classs) >= 0;
}
return false;
})
)
.subscribe((event: MouseEvent) => {
this.div = this.elementRef.nativeElement.childNodes[0];
this.rect = this.div.getBoundingClientRect();
this.origin = { x: event.screenX, y: event.screenY };
this.onDrag = true;
const className = (event.target as any).className.split(' ');
this.typeDrag =className.indexOf('cell-top')>=0?TypeDrag.Move:
(this.classNames.indexOf(className[0])) as TypeDrag;
//acording the typeDrag, I store in "this.incr" the move
this.incr =
this.typeDrag == TypeDrag.Move
? [1, 0, 1, 0]
: this.typeDrag == TypeDrag.Top
? [1, -1, 0, 0]
: this.typeDrag == TypeDrag.Bottom
? [0, 1, 0, 0]
: this.typeDrag == TypeDrag.Right
? [0, 0, 0, 1]
: this.typeDrag == TypeDrag.Left
? [0, 0, 1, -1]
: this.typeDrag == TypeDrag.TopRight
? [1, -1, 0, 1]
: this.typeDrag == TypeDrag.TopLeft
? [1, -1, 1, -1]
: this.typeDrag == TypeDrag.BottomRight
? [0, 1, 0, 1]
: [0, 1, 1, -1];
this.onDrag = true;
/*Not necesary
//remove the "margin" in modal-dialog
const modalContent=this.findModalContent(this.div.parentElement)
if (modalContent)
modalContent.style.margin=0;
*/
//we subscribe to mouseUp
fromEvent(document, 'mouseup')
.pipe(take(1))
.subscribe(() => {
if (this.moveSubscription) {
this.moveSubscription.unsubscribe();
this.moveSubscription = undefined;
this.onDrag = false;
}
});
//we subscribe to mouseMove
if (!this.moveSubscription) {
this.moveSubscription = fromEvent(document, 'mousemove').pipe(
startWith({screenY:this.origin.y,screenX:this.origin.x})
).subscribe(
(moveEvent: MouseEvent) => {
const incrTop = moveEvent.screenY - this.origin.y;
const incrLeft = moveEvent.screenX - this.origin.x;
const width = this.rect.width + this.incr[3] * incrLeft;
const heigth = this.rect.height + this.incr[1] * incrTop;
/*before
this.style = {
position: 'absolute',
'z-index': 1051,
'background-color': this.backgroundColor,
top: this.rect.top + this.incr[0] * incrTop + 'px',
height: (heigth < 75 ? 75 : heigth) + 'px',
left: this.rect.left + this.incr[2] * incrLeft + 'px',
width: (width < 50 ? 50 : width) + 'px'
};
*/
//now:
this.modalContent.style['max-width']=
(width < 50 ? 50 : width) + 'px'
this.modalContent.style['margin-top']=
this.rect.top + this.incr[0] * incrTop + 'px'
this.modalContent.style['margin-left']=
this.rect.left + this.incr[2] * incrLeft + 'px'
this.style={
width:(width < 50 ? 50 : width-1) + 'px',
height:(heigth < 75 ? 75 : heigth-1) + 'px'
}
});
}
}
使用简单,例如(查看如何指示“dragHolder”)
<ng-template #content let-modal>
<angular-window [dragHolder]="header">
<div class="modal-header">
<h4 #header class="modal-title w-100"
id="modal-basic-title">Profile update</h4>
</div>
<div class="modal-body">
</div>
<div class="modal-footer">
</div>
</angular-window>
</ng-template>
注意:要更改 dragHolder 中的光标,我们需要添加 class
.cell-top {
cursor: move;
}
我正在尝试将 bootstrap https://ng-bootstrap.github.io/#/components/modal/examples
版本 4 与 Angular 8 一起使用。我想让模态可调整大小并可拖动。我看到了一些其他版本的例子,比如 3.xx 但 angular - http://jsfiddle.net/GDVdN/
Bootstrap4 的任何参考 ANgular 8 - 模态可调整大小 + 可拖动?
我最接近的是创建一个组件,使内部的任何元素“可调整大小”。
更新:“玩”“modal-dialog”风格
想象一下这样的组件
<div class="resizable" [ngStyle]="style">
<ng-content></ng-content>
<div class="cell-border-top"></div>
<div class="cell-border-bottom"></div>
<div class="cell-border-left"></div>
<div class="cell-border-right"></div>
<div class="cell-top-right"></div>
<div class="cell-bottom-right"></div>
<div class="cell-top-left"></div>
<div class="cell-bottom-left"></div>
</div>
.css 使得divs 是左、右、上、下和四个角的位置
我们监听 mouseDown,并“获取”class我们可以将拖动类型存储在变量中的名称
export enum TypeDrag {
Move,
Top,
Bottom,
Left,
Right,
TopRight,
BottomRight,
TopLeft,
BottomLeft
}
当鼠标按下时,我们订阅 mouseUp 和 mouseMove,mouseUp 简单地删除对 mouseMove 的订阅
mouseMove改变样式div改变位置和尺寸
我们需要将 ElementRef 指定为 Input 以拖动“modal”
还有一个额外的考虑是 ngb-modal 将模态更改为“margin-left”和“margin-top”,所以我需要将 margin 设置为 0 到 a div 带有 calssName==“模态对话框”。为此,我们创建一个递归函数
为了获得“模态对话框”,我们使用递归函数
findModalContent(element:HTMLElement)
{
return element.className=="modal-dialog"?element:
element.parentElement?this.findModalContent(element.parentElement):
null
}
我尽量在代码中用注释来解释
通常这是 stackblitz
@Component({
selector: 'angular-window',
templateUrl: './angular-window.component.html',
styleUrls: ['./angular-window.component.css']
})
export class AngularWindowComponent implements OnInit {
rect: any;
incr: number[] = [0, 0, 0, 0];
nativeElement: any;
typeDrag: TypeDrag;
origin: any;
onDrag: boolean = false;
moveSubscription: any;
//div: any; <--remove in the updated
classNames = [
'cell-top',
'cell-border-top',
'cell-border-bottom',
'cell-border-left',
'cell-border-right',
'cell-top-right',
'cell-bottom-right',
'cell-top-left',
'cell-bottom-left'
];
style: any = null;
constructor(private elementRef: ElementRef) {}
@Input() set dragHolder(value) { //the drag holder will be a
//template reference variable
//we add the class "cell-top"
value.classList.add("cell-top");
}
/*It's not necesary now
//I need indicate the background-color
@Input('background-color') backgroundColor = 'white';
*/
ngOnInit(): void {
//get the "modalContent"
this.modalContent=this.findModalContent(this.elementRef.nativeElement)
//we subscribe to mouseDown
fromEvent(this.elementRef.nativeElement, 'mousedown')
.pipe(
//we filter, only get if the className of element
//is one of the indicate by the variable "classNames"
//or if the className include the "cell-top"
filter((event: MouseEvent) => {
const classs = (event.target as any).className;
if (classs && typeof classs === 'string') {
const className = classs.split(' ');
return className.indexOf("cell-top")>=0?true:
this.classNames.indexOf(classs) >= 0;
}
return false;
})
)
.subscribe((event: MouseEvent) => {
this.div = this.elementRef.nativeElement.childNodes[0];
this.rect = this.div.getBoundingClientRect();
this.origin = { x: event.screenX, y: event.screenY };
this.onDrag = true;
const className = (event.target as any).className.split(' ');
this.typeDrag =className.indexOf('cell-top')>=0?TypeDrag.Move:
(this.classNames.indexOf(className[0])) as TypeDrag;
//acording the typeDrag, I store in "this.incr" the move
this.incr =
this.typeDrag == TypeDrag.Move
? [1, 0, 1, 0]
: this.typeDrag == TypeDrag.Top
? [1, -1, 0, 0]
: this.typeDrag == TypeDrag.Bottom
? [0, 1, 0, 0]
: this.typeDrag == TypeDrag.Right
? [0, 0, 0, 1]
: this.typeDrag == TypeDrag.Left
? [0, 0, 1, -1]
: this.typeDrag == TypeDrag.TopRight
? [1, -1, 0, 1]
: this.typeDrag == TypeDrag.TopLeft
? [1, -1, 1, -1]
: this.typeDrag == TypeDrag.BottomRight
? [0, 1, 0, 1]
: [0, 1, 1, -1];
this.onDrag = true;
/*Not necesary
//remove the "margin" in modal-dialog
const modalContent=this.findModalContent(this.div.parentElement)
if (modalContent)
modalContent.style.margin=0;
*/
//we subscribe to mouseUp
fromEvent(document, 'mouseup')
.pipe(take(1))
.subscribe(() => {
if (this.moveSubscription) {
this.moveSubscription.unsubscribe();
this.moveSubscription = undefined;
this.onDrag = false;
}
});
//we subscribe to mouseMove
if (!this.moveSubscription) {
this.moveSubscription = fromEvent(document, 'mousemove').pipe(
startWith({screenY:this.origin.y,screenX:this.origin.x})
).subscribe(
(moveEvent: MouseEvent) => {
const incrTop = moveEvent.screenY - this.origin.y;
const incrLeft = moveEvent.screenX - this.origin.x;
const width = this.rect.width + this.incr[3] * incrLeft;
const heigth = this.rect.height + this.incr[1] * incrTop;
/*before
this.style = {
position: 'absolute',
'z-index': 1051,
'background-color': this.backgroundColor,
top: this.rect.top + this.incr[0] * incrTop + 'px',
height: (heigth < 75 ? 75 : heigth) + 'px',
left: this.rect.left + this.incr[2] * incrLeft + 'px',
width: (width < 50 ? 50 : width) + 'px'
};
*/
//now:
this.modalContent.style['max-width']=
(width < 50 ? 50 : width) + 'px'
this.modalContent.style['margin-top']=
this.rect.top + this.incr[0] * incrTop + 'px'
this.modalContent.style['margin-left']=
this.rect.left + this.incr[2] * incrLeft + 'px'
this.style={
width:(width < 50 ? 50 : width-1) + 'px',
height:(heigth < 75 ? 75 : heigth-1) + 'px'
}
});
}
}
使用简单,例如(查看如何指示“dragHolder”)
<ng-template #content let-modal>
<angular-window [dragHolder]="header">
<div class="modal-header">
<h4 #header class="modal-title w-100"
id="modal-basic-title">Profile update</h4>
</div>
<div class="modal-body">
</div>
<div class="modal-footer">
</div>
</angular-window>
</ng-template>
注意:要更改 dragHolder 中的光标,我们需要添加 class
.cell-top {
cursor: move;
}