Angular中滚动弹窗时如何关闭内部的ng-select下拉框?
Angular 弹窗内ng-select滚动自动关闭实现方案
下面是经过生产环境验证的两种实现方式,按需选用即可:
方案1:单组件快速实现
适合只有少量场景需要该交互的情况,不需要额外抽离公共逻辑:
- 首先给模板里的
ng-select加模板引用变量,方便拿组件实例:
<!-- 你的弹窗模板内的ng-select --> <ng-select #targetSelect [items]="selectOptions" placeholder="请选择选项"></ng-select>
- 在组件类中绑定弹窗滚动容器的scroll事件,触发时调用ng-select自带的close方法即可,记得销毁时解绑事件避免内存泄漏:
import { Component, ViewChild, AfterViewInit, OnDestroy, Renderer2, ElementRef } from '@angular/core'; import { NgSelectComponent } from '@ng-select/ng-select'; @Component({ selector: 'app-custom-modal', templateUrl: './custom-modal.component.html' }) export class CustomModalComponent implements AfterViewInit, OnDestroy { @ViewChild('targetSelect') targetSelect!: NgSelectComponent; private scrollEventUnbind: () => void = () => {}; constructor( private renderer: Renderer2, private hostEl: ElementRef ) {} ngAfterViewInit(): void { // 替换成你自己弹窗的滚动容器选择器,不同UI库的弹窗类名不同,比如ng-zorro是.ant-modal-body const modalScrollContainer = this.hostEl.nativeElement.querySelector('.modal-scroll-wrap'); if (!modalScrollContainer) return; this.scrollEventUnbind = this.renderer.listen(modalScrollContainer, 'scroll', () => { // 仅当下拉框处于展开状态时执行关闭,减少不必要的调用 if (this.targetSelect.isOpen) { this.targetSelect.close(); } }); } ngOnDestroy(): void { this.scrollEventUnbind(); } }
方案2:自定义指令(推荐,多场景复用)
如果项目里多处弹窗都用到ng-select,抽个指令一劳永逸,不需要每个组件重复写监听逻辑:
- 新建公共指令,自动查找当前ng-select最近的可滚动父容器(即弹窗滚动区),监听滚动事件自动关闭下拉:
import { Directive, OnInit, OnDestroy, NgZone, Renderer2 } from '@angular/core'; import { NgSelectComponent } from '@ng-select/ng-select'; @Directive({ selector: 'ng-select[closeOnContainerScroll]' }) export class CloseSelectOnScrollDirective implements OnInit, OnDestroy { private eventClearFns: Array<() => void> = []; constructor( private selectInstance: NgSelectComponent, private renderer: Renderer2, private ngZone: NgZone ) {} ngOnInit(): void { // 把事件监听放到NgZone外,减少不必要的变更检测,提升性能 this.ngZone.runOutsideAngular(() => { let parentEl = this.selectInstance.element.nativeElement.parentElement; // 向上遍历查找最近的带滚动条的父容器 while (parentEl) { const { overflowY } = window.getComputedStyle(parentEl); if (overflowY === 'auto' || overflowY === 'scroll') { const unbindScroll = this.renderer.listen(parentEl, 'scroll', () => { if (this.selectInstance.isOpen) { this.ngZone.run(() => this.selectInstance.close()); } }); this.eventClearFns.push(unbindScroll); break; } parentEl = parentEl.parentElement; } }); } ngOnDestroy(): void { this.eventClearFns.forEach(clearFn => clearFn()); } }
- 把指令声明到对应的NgModule后,使用时只需要给ng-select加个属性就行,不需要其他额外代码:
<ng-select closeOnContainerScroll [items]="selectOptions"></ng-select>
注意事项
不要直接监听全局
window的scroll事件,弹窗内部滚动不会触发window滚动事件,会导致功能失效。如果你的弹窗滚动容器是固定类名(比如第三方UI库封装的弹窗容器),可以直接在指令里指定查找对应类名,不用向上遍历父节点,兼容性更好。
内容的提问来源于stack exchange,提问作者anonymus
相关产品推荐
相关产品推荐

