滚动时重新定位 CdkConnectedOverlay

cor*_*ory 7 angular-cdk

我试图用来CdkConnectedOverlay在单击按钮时显示叠加层。它主要工作,但覆盖层没有在滚动时重新定位。我确定我遗漏了一些小东西,但我终生无法弄清楚。

我正在使用Angular 7.2.8Angular CDK 7.3.3

认为这可能与缺少 cdk 样式有关(类似于),但我导入了它们;如果样式丢失,我希望它首先不能正确显示。我的只是不会在滚动上重新定位。

模板:

<button
  (click)="isOpen = !isOpen"
  cdkOverlayOrigin
  #trigger="cdkOverlayOrigin"
>Show</button>

<ng-template
  cdkConnectedOverlay
  [cdkConnectedOverlayOrigin]="trigger"
  [cdkConnectedOverlayOpen]="isOpen"
>
 Popover content
</ng-template>
Run Code Online (Sandbox Code Playgroud)

成分:

@Component ( {
  selector: 'app-popover',
  templateUrl: './popover.component.html',
  styleUrls: [ './popover.component.css' ],
  changeDetection: ChangeDetectionStrategy.OnPush,
} )
export class PopoverComponent {
  isOpen: boolean = false;
}
Run Code Online (Sandbox Code Playgroud)

还有一个显示问题的 Plunkr:https ://stackblitz.com/edit/angular-7-popover

更新

滚动重新定位问题仅在弹出框位于以overflow: auto. 如果页面溢出,那么它工作正常。您可以使用以下模板查看此行为

<div style="height: 300px; overflow-y: auto">
  <!-- Scroll re-positioning does not work when scrolling in here -->
  <div style="height: 100px"></div>
  <app-popover>
    Popover content
  </app-popover>
  <div style="height: 400px"></div>
</div>

<div style="height: 100px;"></div>
<!-- Scroll re-positioning works when scrolling here -->
<app-popover>
  Popover content
</app-popover>
<div style="height: 1200px;"></div>
Run Code Online (Sandbox Code Playgroud)

我还更新了 stackblitz 以显示此问题。

ysf*_*ysf 11

cdk 文档有时不容易理解,而且到处都是隐藏的宝石:)

在这里它指出;

每个策略通常会注入 ScrollDispatcher(来自@angular/cdk/scrolling)以在滚动发生时得到通知。

我从这句话中理解的是,Overlay重新定位自己以响应来自ScrollDispatcher. 那么,这些滚动事件从何而来?

不幸的是,文档中没有关于此的任何信息。所以我查看了代码并找到了这个

  /** Sets up the global scroll listeners. */
  private _addGlobalListener() {
    this._globalSubscription = this._ngZone.runOutsideAngular(() => {
      return fromEvent(window.document, 'scroll').subscribe(() => this._scrolled.next());
    });
}
Run Code Online (Sandbox Code Playgroud)

这意味着默认ScrollDispatcher监听window 上的滚动事件。

在上面的情况下,它会在滚动窗口而不是内部容器时响应事件。这与我们目前收集到的信息相符。

在这里我们可以得出结论,Overlay即不会通知内部容器内发生的滚动事件,我们需要做的就是向内部容器注册ScrollDispatcher

此时cdkScrollable指令进入救援并放置cdkScrollable在滚动内部容器上解决了问题。

  /** Sets up the global scroll listeners. */
  private _addGlobalListener() {
    this._globalSubscription = this._ngZone.runOutsideAngular(() => {
      return fromEvent(window.document, 'scroll').subscribe(() => this._scrolled.next());
    });
}
Run Code Online (Sandbox Code Playgroud)

这是一个工作演示

  • 对于那些需要它的人,为了让 cdkScrollable 工作,您需要导入 ScrollingModule。`从 '@angular/cdk/scrolling' 导入 {ScrollingModule};` ..... `导入:[ ....., ScrollingModule]` (4认同)
  • 啊,现在有道理了!大约在你发布这个答案的同时,我也在 Github 上遇到了这个问题,基本上说的是同一件事。https://github.com/angular/components/issues/6157 (2认同)