How to keep Angular CDK Overlay component within page based on page offset
我正在图书馆Contexr上工作。 我只是将应用程序重构为使用Angular CDK Overlay来显示上下文菜单,因此我不再需要在实际应用程序中包括某些组件(减少了一个安装步骤)。
我曾经使用FlexibleConnectedPositionStrategy在元素下面创建一个下拉列表,该下拉列表将保留在页面内。 可以使用ElementRef来创建此排名策略:
1 2 3 4 | const positionStrategy = this.overlay.position() .flexibleConnectedTo(elementRef) .left(state.left + 'px') .top(state.top + 'px'); |
问题是我没有ElementRef。 我的叠加层应灵活连接到.left()和.top()。 是否可以通过FlexibleConnectedPositionStrategy做到这一点? 目前,我正在尝试使用GlobalPositionStrategy,但这不能解释屏幕外的元素。
打开覆盖的类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | @Injectable({ providedIn: 'root' }) export class ContextMenuService { private overlayRef: OverlayRef; constructor(private overlay: Overlay, private injector: Injector) {} public open(state: ContextState) { const overlayConfig = this.getOverlayConfig(state); this.overlayRef = this.overlay.create(overlayConfig); const contextMenuRef = new ContextMenuOverlayRef(this.overlayRef); this.attachDialogContainer(this.overlayRef, state, contextMenuRef); } private getOverlayConfig(state: ContextState) { const positionStrategy = this.overlay.position() .global() .left(state.left + 'px') .top(state.top + 'px'); return { positionStrategy: positionStrategy }; } private createInjector(state: ContextState, dialogRef: ContextMenuOverlayRef) { const injectionTokens = new WeakMap(); injectionTokens.set(ContextMenuOverlayRef, dialogRef); injectionTokens.set(CONTEXT_MENU_OVERLAY_DATA, state); return new PortalInjector(this.injector, injectionTokens); } private attachDialogContainer(overlayRef: OverlayRef, state: ContextState, contextMenuOverlayRef: ContextMenuOverlayRef) { const injector = this.createInjector(state, contextMenuOverlayRef); const containerPortal = new ComponentPortal(ContextMenuComponent, null, injector); overlayRef.attach(containerPortal); } public close() { if (this.overlayRef) { this.overlayRef.dispose(); } } } |
事实证明,您毕竟可以使用FlexibleConnectedPositionStrategy。 我在Github上找到了一个名为ngrx-rightclick的上下文菜单库(谢谢!)。 他们在这里基于click事件创建了一个新的ElementRef。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | private getOverlayConfig(event: MouseEvent, state: ContextState) { const target = { getBoundingClientRect: (): ClientRect => ({ bottom: event.clientY, height: 0, left: event.clientX, right: event.clientX, top: event.clientY, width: 0, }), }; const element = new ElementRef(target); const positionStrategy = this.overlay.position() .flexibleConnectedTo(element) .withFlexibleDimensions(false) .withPositions([ { originX: 'end', originY: 'top', overlayX: 'start', overlayY: 'top', }, { originX: 'start', originY: 'top', overlayX: 'end', overlayY: 'top', }, { originX: 'end', originY: 'bottom', overlayX: 'start', overlayY: 'bottom', }, { originX: 'start', originY: 'bottom', overlayX: 'end', overlayY: 'bottom', }, ]); return { positionStrategy: positionStrategy }; } |
我查看了GitHub中的源代码。 由于您使用指令将上下文菜单附加到元素,因此您还可以在指令中获取元素引用。 只需将其添加到指令的构造函数中,然后将其发送到您的服务即可使用。 这是修改您的类以获取ElementRef的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | import {Directive, HostListener, Input} from '@angular/core'; import {ContexrService} from '../providers/contexr.service'; @Directive({ selector: '[ctx]' }) export class ContextDirective { @Input('ctx') ctx: string; @Input('ctxArgs') ctxArgs: any; constructor(private contexr: ContexrService, private elementRef: ElementRef) {} @HostListener('contextmenu', ['$event']) @HostListener('click', ['$event']) public onContextMenu(event) { this.contexr.addCurrentContext(this.ctx, this.ctxArgs, this.elementRef); } } |