To achieve this goal, there are various methods that can be utilized. However, if you are already utilizing @angular/material
, you have the option to make use of @angular/cdk
along with its ScrollDispatchModule
(refer to the documentation).
This approach allows for a simple and efficient way to observe scroll events for registered elements, outside of NgZone, thereby minimizing performance impact.
Take a look at the sample stackblitz:
https://stackblitz.com/edit/angular-npdbtp
Firstly, ensure to import the ScrollDispatchModule
and register a provider for ScrollDispatcher
:
import {ScrollDispatchModule, ScrollDispatcher} from '@angular/cdk/scrolling';
@NgModule({
imports: [
(other imports)
ScrollDispatchModule
],
providers: [ScrollDispatcher]
})
export class AppModule {}
Next, in your template, designate an html element with the cdkScrollable
directive. This will automatically enlist it in the ScrollDispatcher
. Additionally, you can bind the style of the component (e.g., opacity) to a property defined within your component:
<div class="scroll-wrapper" cdkScrollable>
<mat-toolbar class="sticky-toolbar" [style.opacity]="opacity">My App</mat-toolbar>
<div>content</div>
</div>
To implement sticky behavior on an html element, utilize the display: sticky
rule in conjunction with top: 0
:
.sticky-toolbar {
position: sticky;
top: 0px;
}
Subsequently, inject the ScrollDispatcher
and NgZone
into your component while defining the opacity property:
opacity = 1;
constructor(
private scrollDispatcher: ScrollDispatcher,
private zone: NgZone
) {}
Then, subscribe to scrolled events emitted by the ScrollDispatcher. These events are triggered for all registered components. If necessary, also refer to the documentation for registering to scroll events of a specific element.
ngOnInit(): void {
this.scrollDispatcher.scrolled().subscribe((event: CdkScrollable) => {
const scroll = event.measureScrollOffset("top");
let newOpacity = this.opacity;
if (scroll > 0) {
newOpacity = 0.75;
} else {
newOpacity = 1;
}
if (newOpacity !== this.opacity) {
this.zone.run(() => {
this.opacity = newOpacity;
});
}
});
}
The ScrollDispatcher
operates outside of NgZone, ensuring that change detection is not applied across the entire application. This results in enhanced performance, which is why we include NgZone and execute property changes within the zone to trigger proper change detection throughout the component tree.