nz-modal、nz-drawer等出现滚动条(非body的内的滚动),nz-select下拉框错位问题

271 阅读1分钟

问题原因分析。

  • 初始化时,下来位置就通过目标元素(nz-select等)确定下来了。所以随内容元素的滚动不会在重新计算下拉框的位置。从而出现错位问题(感兴趣可以去看下nz-dropdown是怎么生成的)

解决方式

  • 既然知道原因了,那就可以通过监听滚动,不断重新计算nz-dropdown的位置
  • 以为nz-select的例子为例,代码如下
// .html
<button nz-button (click)="createModal()" [nzType]="'dashed'" [nzSize]="'small'">
    <span>test select</span>
</button>
<template #detialModal>
    <div>123456456</div>
</template>
<ng-template #detialModal>
    <div #onModalContentScroll>
        <nz-select [(ngModel)]="selectedValue" nzAllowClear nzPlaceHolder="Choose" nzShowSearch
            class="width-100">
            <nz-option-group nzLabel="Manager">
                <nz-option nzValue="jack" nzLabel="Jack"></nz-option>
                <nz-option nzValue="lucy" nzLabel="Lucy"></nz-option>
            </nz-option-group>
            <nz-option-group nzLabel="Engineer">
                <nz-option nzValue="tom" nzLabel="Tom"></nz-option>
            </nz-option-group>
        </nz-select>
        <div style="height: 800px;">撑大modal内容</div>
    </div>
</ng-template>

// .ts
import { Component, NgZone, TemplateRef, ViewChild, ViewChildren, QueryList } from '@angular/core';
import { NzModalRef, NzModalService } from 'ng-zorro-antd/modal';
import { NzSelectComponent } from 'ng-zorro-antd/select';
import { take } from 'rxjs';

@Component({
  selector: 'app-dome',
  templateUrl: './dome.component.html',
  styleUrls: ['./dome.component.less']
})
export class DomeComponent {
  @ViewChild('detialModal', { static: true }) detialModal!: TemplateRef<{}>;
  // Angular 推荐使用非空断言操作符 `!` 来标记这些属性,以确保它们在使用时已经被初始化了。
  @ViewChildren(NzSelectComponent) selectRefs!: QueryList<NzSelectComponent>;
  selectedValue = 'lucy';
  modalRef!: NzModalRef;
  constructor(private modal: NzModalService, private ngZone: NgZone) { }
  createModal() {
    this.modalRef = this.modal.create({
      nzTitle: 'Modal Title',
      nzContent: this.detialModal,
      nzClosable: false,
      nzOnOk: () => new Promise(resolve => setTimeout(resolve, 1000))
    });
     // 定义滚动事件监听器
    this.modal.afterOpen.subscribe(() => {
      // 打开弹窗时,可能下拉实列还未初始化完成;所以需要ngZone
      this.ngZone.onStable
        .asObservable()
        .pipe(take(1))
        .subscribe(() => {
          const modalContentElement =
            this.modal.containerInstance.modalElementRef.nativeElement
              .parentElement;
          if (modalContentElement) {
            modalContentElement.addEventListener('scroll', scrollListener);
          }
        });
    });
    this.modal.afterClose.subscribe(() => {
      const modalContentElement =
        this.modal.containerInstance.modalElementRef.nativeElement
          .parentElement;
      if (modalContentElement) {
        modalContentElement.removeEventListener('scroll', scrollListener);
      }
    });
  }
}