假设我想知道组件中的特定子元素何时滚动。假设我声明:
contentPanel = viewChild.required<ElementRef>('contentPanel');
contentScrollTop = computed(
() => this.contentPanel().nativeElement.scrollTop,
);
然后在构造函数中出现如下效果:
effect(() => {
console.log('scrolltop: ', this.contentScrollTop());
});
所以这实际上不起作用,但是......这种方法有办法起作用吗?或者 nativeElement 的属性是否超出了 Signals 可以检测到的变化?我可以使用事件侦听器轻松地做到这一点,只是好奇是否有更多信号方式来做到这一点。
截至 2024 年 12 月 14 日,HTML 元素中没有
HostListener
信号或 listening
事件信号。
在那之前我们必须想办法来实现这一点,我可以想到两种方法。
使用
fromEvent
scroll
监听更改,我们必须确保在 ngAfterViewInit
上完成此操作,因为viewChild
信号将在此处具有值。
我正在使用
takeUntilDestroyed
和 destroyRef
在组件销毁时自动销毁侦听器。
然后我们使用
tap
将事件值设置为信号contentScrollTop
,您可以使用它来实现信号的反应性。
destroyRef = inject(DestroyRef);
contentPanel = viewChild.required<ElementRef>('contentPanel');
contentScrollTop = signal(0);
ngAfterViewInit() {
console.log(this.contentPanel());
fromEvent(this.contentPanel().nativeElement, 'scroll')
.pipe(
startWith(this.contentPanel().nativeElement?.scrollTop),
takeUntilDestroyed(this.destroyRef),
tap((response: any) => {
this.contentScrollTop.set(response.target?.scrollTop);
})
)
.subscribe();
}
import {
Component,
DestroyRef,
ElementRef,
inject,
signal,
viewChild,
} from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { toSignal, takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { fromEvent, tap, startWith } from 'rxjs';
@Component({
selector: 'app-root',
template: `
<div style="height:300px;overflow:auto;border:1px solid black" #contentPanel >
<div style="height:1000px">
Scrollable content!
</div>
</div>
{{contentScrollTop()}}
`,
})
export class App {
destroyRef = inject(DestroyRef);
contentPanel = viewChild.required<ElementRef>('contentPanel');
contentScrollTop = signal(0);
ngAfterViewInit() {
console.log(this.contentPanel());
fromEvent(this.contentPanel().nativeElement, 'scroll')
.pipe(
startWith(this.contentPanel().nativeElement?.scrollTop),
takeUntilDestroyed(this.destroyRef),
tap((response: any) => {
this.contentScrollTop.set(response.target?.scrollTop);
})
)
.subscribe();
}
}
bootstrapApplication(App);