рдЕрднреА рдПрдХ рдЕрд╡рд▓реЛрдХрди рдпреЛрдЧреНрдп рдкрд╛рд╕ рдХрд░рдирд╛ рд╕рдВрднрд╡ рд╣реИ рдЬреЛ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХрд╛ рд╡рд┐рд╕реНрддрд╛рд░ рдХрд░рдиреЗ рдХрд╛ рдПрдХ рд╢рд╛рдирджрд╛рд░ рддрд░реАрдХрд╛ рд╣реИред рд╣рд╛рд▓рд╛рдБрдХрд┐, рдпрд╣ рдереЛрдбрд╝рд╛ рд╕реАрдорд┐рдд рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдЙрдкрдпреЛрдЧреЛрдВ рдХреЛ рд╕рд░рд▓ рддрд░реАрдХреЗ рд╕реЗ рдЫрд╡рд┐ рддрдХ рдкрд╣реБрдБрдЪ рдирд╣реАрдВ рдорд┐рд▓ рд╕рдХрддреА рд╣реИред
рд╕рдмрд╕реЗ рдЖрдо рдореБрджреНрджреЛрдВ рдореЗрдВ рд╕реЗ рдПрдХ рдпрд╣ рд╣реИ рдХрд┐ рдЬрдм рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд╕реНрдХреНрд░реЙрд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╡рд┐рдВрдбреЛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ рдпрд╛ 3-рднрд╛рдЧ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ рдЬреЛ рдЕрддрд┐рд░рд┐рдХреНрдд рд╕реНрдХреНрд░реЙрд▓ рдкрд░рддреЗрдВ рдЬреЛрдбрд╝рддрд╛ рд╣реИ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП рдЖрдпрдирд┐рдХ, рдПрдирдЬреА рд╕рд╛рдордЧреНрд░реА рдбрд┐рдЬрд╝рд╛рдЗрди, рдЖрджрд┐), рдФрд░ рдХрднреА-рдХрднреА рдЗрд╕реЗ рдвреВрдВрдврдирд╛ рдореБрд╢реНрдХрд┐рд▓ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдХреМрди рд╕рд╛ рддрддреНрд╡ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рд╕реНрдХреНрд░реЙрд▓ рдХрд░рддрд╛ рд╣реИред рдЗрд╕реЗ рд╣рд▓ рдХрд░рдиреЗ рдХрд╛ рдПрдХ рддрд░реАрдХрд╛ Intersection Observer
рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ (рдЬреЛ рдкреНрд░рджрд░реНрд╢рди рдХреЛ рдмрдврд╝рд╛рд╡рд╛ рднреА рджреЗ рд╕рдХрддрд╛ рд╣реИ)ред рдЙрджрд╛.
@Component({
selector: 'intersection-observer',
template: `<img #img [defaultImage]="defaultImage" [lazyLoad]="image" [scrollObservable]="subject">`,
})
export class IntersectionObserverComponent {
@ViewChild('img') img;
subject = new Subject();
defaultImage = 'https://www.placecage.com/1000/1000';
image = 'https://images.unsplash.com/photo-1467932760935-519284fc87fa?dpr=2&auto=compress,format&fit=crop&w=1199&h=800&q=80';
ngAfterViewInit() {
const config = {
rootMargin: '50px 50px',
threshold: 0.01
};
function onIntersection(entries) {
entries.forEach(entry => {
if (entry.intersectionRatio > 0) {
observer.unobserve(entry.target);
this.subject.next();
}
});
}
const observer = new IntersectionObserver(onIntersection, config);
observer.observe(this.img.nativeElement);
}
}
рд╣рд╛рд▓рд╛рдВрдХрд┐ рдпрд╣ рдХрд╛рдлреА рдмреЛрдЭрд┐рд▓ рд╣реИред
рд╣рдо рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдХреЛ scrollObservable
рд░реВрдк рдореЗрдВ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреНрдпрд╛ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдХреБрдЫ рдРрд╕рд╛:
if (!this.scrollObservable) {
const windowTarget = isWindowDefined() ? window : undefined;
scrollObservable = getScrollListener(this.scrollTarget || windowTarget);
} else if (typeof this.scrollObservable === 'function') {
scrollObservable = this.scrollObservable(image, offset) // and maybe more
} else {
scrollObservable = this.scrollObservable.startWith('');
}
рд╣рдо рдЙрдкрд░реЛрдХреНрдд рдШрдЯрдХ рдХреЛ рдлрд┐рд░ рд╕реЗ рдирд╣реАрдВ рд▓рд┐рдЦ рд╕рдХрддреЗ рд╣реИрдВ:
@Component({
selector: 'intersection-observer',
template: `<img [defaultImage]="defaultImage" [lazyLoad]="image"
[scrollObservable]="startLazyload" offest="50">`,
})
export class IntersectionObserverComponent {
defaultImage = 'https://www.placecage.com/1000/1000';
image = 'https://images.unsplash.com/photo-1467932760935-519284fc87fa?dpr=2&auto=compress,format&fit=crop&w=1199&h=800&q=80';
startLazyload(image, offset) {
Observable.create(observer => {
const intersectionObserver = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.intersectionRatio > 0) {
observer.next();
}
});
}, {
rootMargin: offset ? `${offset}px` : undefined,
threshold: 0.01
});
intersectionObserver.observe(image);
return () => observer.unobserve(image);
});
}
}
рдмреЗрд╣рддрд░ рд▓реЗрдХрд┐рди рдлрд┐рд░ рднреА рдереЛрдбрд╝рд╛ рд╢реЛрд░, рдЦрд╛рд╕рдХрд░ рдЬрдм рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд╕рднреА рдЫрд╡рд┐рдпреЛрдВ рдкрд░ IntersectionObserver
рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реИред
рдЗрд╕реЗ рд╣рд▓ рдХрд░рдиреЗ рдХрд╛ рдПрдХ рддрд░реАрдХрд╛ NgModule
рдореЗрдВ рдПрдХ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдЕрд╡рд▓реЛрдХрди рдпреЛрдЧреНрдп рднреА рд╣реЛ рд╕рдХрддрд╛ рд╣реИ:
import { intersectionObserverLazyLoad } from 'some-place';
@NgModule({
declarations: [ AppComponent ],
imports: [ BrowserModule, lazyLoadImage({
observable: intersectionObserverLazyLoad
})],
bootstrap: [ AppComponent ]
})
export class MyAppModule {}
рд╣рдо рдЙрдкрд░реЛрдХреНрдд рдШрдЯрдХ рдХреЛ рдлрд┐рд░ рд╕реЗ рдирд╣реАрдВ рд▓рд┐рдЦ рд╕рдХрддреЗ рд╣реИрдВ:
@Component({
selector: 'intersection-observer',
template: `<img [defaultImage]="defaultImage" [lazyLoad]="image" offest="50">`,
})
export class IntersectionObserverComponent {
defaultImage = 'https://www.placecage.com/1000/1000';
image = 'https://images.unsplash.com/photo-1467932760935-519284fc87fa?dpr=2&auto=compress,format&fit=crop&w=1199&h=800&q=80';
}
NgModule рдореЗрдВ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдлрд╝рдВрдХреНрд╢рдВрд╕ рдкрд╛рд╕ рдХрд░рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ isVisible
рдФрд░ loadImage
рд▓рд┐рдП рдХрд╕реНрдЯрдо рдлрд╝рдВрдХреНрд╢рдВрд╕ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рджрд░рд╡рд╛рдЬреЗ рднреА рдЦреЛрд▓ рд╕рдХрддреА рд╣реИ рд▓реЗрдХрд┐рди рдпрд╣ рдмрд╛рдж рдХреА рдХрд╣рд╛рдиреА рд╣реИред
рд╣рд▓ рдХрд░реЗрдВрдЧреЗ: #287, #195, #286, #285, #275, #259 рдФрд░ рдЕрдзрд┐рдХред рдЕрдзрд┐рдХрд╛рдВрд╢ рдореБрджреНрджреЛрдВ рдХреЛ рдЕрдиреНрдп рддрд░реАрдХреЛрдВ рд╕реЗ рд╣рд▓ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рдЕрдЪреНрдЫрд╛ рд╣реЛрдЧрд╛ рдпрджрд┐ рд╣рдо рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рдЕрд╡рд▓реЛрдХрди рдпреЛрдЧреНрдп рдмрдирд╛рддреЗ рд╕рдордп рдЕрдзрд┐рдХ рд▓рдЪреАрд▓рд╛рдкрди рджреЗ рд╕рдХреЗрдВред
рдЖрдкрдХреЛ рдХреНрдпрд╛ рд▓рдЧрддрд╛ рд╣реИ @sapierens , @rimlin ?
@tjoskar рдХреЗ рд░реВрдк рдореЗрдВ рдореИрдВ рд╕рдордЭрддрд╛ рд╣реВрдБ рдЖрдк рдХреЛ рдмрдврд╝рд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЪрд╛рд╣рддреЗ рд╣реИрдВ scrollObservable
рджреНрд╡рд╛рд░рд╛ рдХреЗ рд▓рд┐рдП рд╡рд┐рдХрд▓реНрдк рдХреЗ рд░реВрдк рдореЗрдВ рд╕рдорд╛рд░реЛрд╣ рдкреНрд░рджрд╛рди scrollObservable
рд╣реИ, рдЬреЛ рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд╕ рдЖ рдЬрд╛рдПрдЧреА, рдЬреЛ рдлреЗрдВрдХрдирд╛ рдЫрд╡рд┐ рд▓реЛрдб рдШрдЯрдирд╛ рдХреЗ рд▓рд┐рдП рдХреМрди рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИ? рдЕрдЧрд░ рдРрд╕рд╛ рд╣реИ, рддреЛ рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЕрдЪреНрдЫрд╛ рд╡рд┐рдЪрд╛рд░ рд╣реИ!
рд▓реЗрдХрд┐рди рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рддрд░реНрдХреЛрдВ рдХреА рдЧрдгрдирд╛ рдХреЗ рдмрдЬрд╛рдп рд╡рд╕реНрддреБ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдмреЗрд╣рддрд░ рд╣реИ:
...
} else if (typeof this.scrollObservable === 'function') {
scrollObservable = this.scrollObservable({
image,
offset
});
} else {
...
рд╕реНрдХреНрд░реЙрд▓рдСрдмреНрдЬрд░реНрд╡реЗрдмрд▓ рдХреЗ рд╡рд┐рдХрд▓реНрдк рдХреЗ рд░реВрдк рдореЗрдВ рдлрд╝рдВрдХреНрд╢рди рдкреНрд░рджрд╛рди рдХрд░реЗрдВ, рдЬреЛ рдСрдмреНрдЬрд░реНрд╡реЗрдмрд▓ рд▓реМрдЯрд╛рдПрдЧрд╛, рдЬреЛ рдЗрдореЗрдЬ рд▓реЛрдб рдЗрд╡реЗрдВрдЯ рдХреЛ рдЙрддреНрд╕рд░реНрдЬрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИ
рд╕рд╣реА рд╣реИ, рдореИрдВ scrollObservable
рдХрд╛ рдирд╛рдо рдмрджрд▓рдирд╛ рднреА рдЪрд╛рд╣ рд╕рдХрддрд╛ рд╣реВрдВ рд▓реЗрдХрд┐рди рдпрд╣ рдПрдХ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдмрджрд▓рд╛рд╡ рд╣реЛрдЧрд╛ред
рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рддрд░реНрдХреЛрдВ рдХреА рдЧрдгрдирд╛ рдХреЗ рдмрдЬрд╛рдп рд╡рд╕реНрддреБ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдмреЗрд╣рддрд░ рд╣реИ
рдЗрд╕ рдмрд╛рдд рд╕реЗ рд╕рд╣рдордд!
рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдПрдХ рдЕрдЪреНрдЫрд╛ рд╡рд┐рдЪрд╛рд░ рд╣реИ, рдЦрд╛рд╕рдХрд░ рдПрдХ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдкрд░реНрдпрд╡реЗрдХреНрд╖рдХ рдкрд╛рд╕ рдХрд░рдирд╛ред
рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рддрд░реНрдХреЛрдВ рдХреА рдЧрдгрдирд╛ рдХреЗ рдмрдЬрд╛рдп рд╡рд╕реНрддреБ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдмреЗрд╣рддрд░ рд╣реИ
рдореИрдВ рднреА рдЗрд╕рд╕реЗ рд╕рд╣рдордд рд╣реВрдВред
#365 рдФрд░ рд╕рдВрд╕реНрдХрд░рдг 2.1.0 . рдореЗрдВ рдлрд┐рдХреНрд╕реНрдб
рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА
@tjoskar рдХреЗ рд░реВрдк рдореЗрдВ рдореИрдВ рд╕рдордЭрддрд╛ рд╣реВрдБ рдЖрдк рдХреЛ рдмрдврд╝рд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЪрд╛рд╣рддреЗ рд╣реИрдВ
scrollObservable
рджреНрд╡рд╛рд░рд╛ рдХреЗ рд▓рд┐рдП рд╡рд┐рдХрд▓реНрдк рдХреЗ рд░реВрдк рдореЗрдВ рд╕рдорд╛рд░реЛрд╣ рдкреНрд░рджрд╛рдиscrollObservable
рд╣реИ, рдЬреЛ рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд╕ рдЖ рдЬрд╛рдПрдЧреА, рдЬреЛ рдлреЗрдВрдХрдирд╛ рдЫрд╡рд┐ рд▓реЛрдб рдШрдЯрдирд╛ рдХреЗ рд▓рд┐рдП рдХреМрди рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИ? рдЕрдЧрд░ рдРрд╕рд╛ рд╣реИ, рддреЛ рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЕрдЪреНрдЫрд╛ рд╡рд┐рдЪрд╛рд░ рд╣реИ!рд▓реЗрдХрд┐рди рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рддрд░реНрдХреЛрдВ рдХреА рдЧрдгрдирд╛ рдХреЗ рдмрдЬрд╛рдп рд╡рд╕реНрддреБ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдмреЗрд╣рддрд░ рд╣реИ: