You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular绑定nz-autocomplete的ScrollEndDirective滚动事件不触发排查

解决Ng-Zorro下拉框滚动触底无响应问题及替代方案

一、Nz-Autocomplete滚动指令修复方案

问题原因

你的自定义指令绑定在nz-autocomplete组件本身,但实际可滚动的是组件内部的下拉菜单容器,而非nz-autocomplete元素本身,所以@HostListener监听的scroll事件不会触发。

修改后的指令代码

import { Directive, ElementRef, EventEmitter, Output, AfterViewInit, Renderer2, OnDestroy } from '@angular/core';

@Directive({
  selector: '[scrollEnd]'
})
export class ScrollEndDirective implements AfterViewInit, OnDestroy {
  @Output() scrolledToEnd = new EventEmitter<boolean>();
  private scrollContainer: HTMLElement | null = null;
  private scrollListener: (() => void) | null = null;

  constructor(private el: ElementRef, private renderer: Renderer2) {
    console.log('constructor logger');
  }

  ngAfterViewInit(): void {
    // 定位nz-autocomplete内部的滚动容器(Ng-Zorro默认类名为ant-autocomplete-dropdown-menu)
    this.scrollContainer = this.el.nativeElement.querySelector('.ant-autocomplete-dropdown-menu');
    if (this.scrollContainer) {
      // 绑定滚动事件监听
      this.scrollListener = this.renderer.listen(this.scrollContainer, 'scroll', () => this.onScroll());
    }
  }

  onScroll(): void {
    if (!this.scrollContainer) return;
    console.log(this.scrollContainer);
    // 兼容像素精度问题,判断滚动是否触底
    const isAtEnd = this.scrollContainer.scrollHeight - this.scrollContainer.scrollTop <= this.scrollContainer.clientHeight + 1;
    this.scrolledToEnd.emit(isAtEnd);
  }

  ngOnDestroy(): void {
    // 销毁监听避免内存泄漏
    if (this.scrollListener) {
      this.scrollListener();
    }
  }
}

说明

  1. 利用AfterViewInit钩子在视图初始化后,查找内部滚动容器元素
  2. 使用Renderer2绑定滚动事件,替代@HostListener
  3. 增加OnDestroy钩子销毁监听,防止内存泄漏
  4. 滚动触底判断增加1px的容错,避免因浏览器像素精度问题导致判断失效

组件用法保持不变,仍将指令绑定在nz-autocomplete上即可。


二、Nz-Select替代方案(更简洁)

如果你愿意切换到Nz-Select,可通过以下配置满足你的需求:

核心配置解决你的痛点

  1. 避免空输入显示NotFoundContent:自定义nzNotFoundContent模板,仅在有搜索输入且无结果时显示
  2. 选中后可清除输入文本:使用nzMode="combobox"模式,允许选中后编辑输入框内容,搭配nzAllowClear支持清除

示例代码

import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Subject } from 'rxjs';
import { switchMap } from 'rxjs/operators';

@Component({
  selector: 'nz-demo-select-infinite',
  template: `
    <nz-select
      nzShowSearch
      nzMode="combobox"
      nzAllowClear
      [(ngModel)]="selectedValue"
      (scrollToBottom)="onScrollEnd()"
      [nzNotFoundContent]="notFoundTpl"
      (nzSearchChange)="onSearch($event)"
      style="width: 200px;"
    >
      <nz-option *ngFor="let option of options" [nzValue]="option.name" [nzLabel]="option.name"></nz-option>
      <ng-template #notFoundTpl>
        <ng-container *ngIf="searchValue && options.length === 0">无匹配结果</ng-container>
      </ng-template>
    </nz-select>
  `,
})
export class NzDemoSelectInfiniteComponent {
  selectedValue?: string;
  options: any[] = [];
  searchValue = '';
  private searchSubject = new Subject<string>();

  constructor(private http: HttpClient) {
    this.searchSubject
      .pipe(switchMap((value) => this.search(value)))
      .subscribe((options) => {
        this.options = options;
      });
  }

  onSearch(value: string): void {
    this.searchValue = value;
    this.searchSubject.next(value);
  }

  search(value: string) {
    return this.http
      .get<any[]>('https://jsonplaceholder.typicode.com/users')
      .pipe(map((response) => response));
  }

  onScrollEnd(): void {
    console.log('Scrollbar is at the end');
    // 在此实现加载更多逻辑
  }
}

说明

  • Nz-Select内置scrollToBottom事件,无需自定义指令即可实现滚动触底监听
  • nzMode="combobox":开启可编辑模式,选中后输入框仍可编辑,支持手动清除内容
  • 自定义nzNotFoundContent:通过条件判断,仅在用户输入搜索内容且无匹配结果时显示提示

内容的提问来源于stack exchange,提问作者Welp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 04:31:00