Ng-lazyload-image: рдлрд╝реАрдЪрд░ рдЕрдиреБрд░реЛрдз: рджреЗрдЦрдиреЗ рдпреЛрдЧреНрдп рдирд┐рд░реНрдорд╛рдг рдореЗрдВ рдЫрд╡рд┐ рддрдХ рдкрд╣реБрдБрдЪ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ

рдХреЛ рдирд┐рд░реНрдорд┐рдд 3 рдлрд╝рд░ре░ 2018  ┬╖  4рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ  ┬╖  рд╕реНрд░реЛрдд: tjoskar/ng-lazyload-image

рдкреНрд░реЗрд░рдгрд╛ рдФрд░ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди

рдЕрднреА рдПрдХ рдЕрд╡рд▓реЛрдХрди рдпреЛрдЧреНрдп рдкрд╛рд╕ рдХрд░рдирд╛ рд╕рдВрднрд╡ рд╣реИ рдЬреЛ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХрд╛ рд╡рд┐рд╕реНрддрд╛рд░ рдХрд░рдиреЗ рдХрд╛ рдПрдХ рд╢рд╛рдирджрд╛рд░ рддрд░реАрдХрд╛ рд╣реИред рд╣рд╛рд▓рд╛рдБрдХрд┐, рдпрд╣ рдереЛрдбрд╝рд╛ рд╕реАрдорд┐рдд рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдЙрдкрдпреЛрдЧреЛрдВ рдХреЛ рд╕рд░рд▓ рддрд░реАрдХреЗ рд╕реЗ рдЫрд╡рд┐ рддрдХ рдкрд╣реБрдБрдЪ рдирд╣реАрдВ рдорд┐рд▓ рд╕рдХрддреА рд╣реИред

рд╕рдмрд╕реЗ рдЖрдо рдореБрджреНрджреЛрдВ рдореЗрдВ рд╕реЗ рдПрдХ рдпрд╣ рд╣реИ рдХрд┐ рдЬрдм рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд╕реНрдХреНрд░реЙрд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╡рд┐рдВрдбреЛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ рдпрд╛ 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 {
...

рд╕рднреА 4 рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

@tjoskar рдХреЗ рд░реВрдк рдореЗрдВ рдореИрдВ рд╕рдордЭрддрд╛ рд╣реВрдБ рдЖрдк рдХреЛ рдмрдврд╝рд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЪрд╛рд╣рддреЗ рд╣реИрдВ scrollObservable рджреНрд╡рд╛рд░рд╛ рдХреЗ рд▓рд┐рдП рд╡рд┐рдХрд▓реНрдк рдХреЗ рд░реВрдк рдореЗрдВ рд╕рдорд╛рд░реЛрд╣ рдкреНрд░рджрд╛рди scrollObservable рд╣реИ, рдЬреЛ рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд╕ рдЖ рдЬрд╛рдПрдЧреА, рдЬреЛ рдлреЗрдВрдХрдирд╛ рдЫрд╡рд┐ рд▓реЛрдб рдШрдЯрдирд╛ рдХреЗ рд▓рд┐рдП рдХреМрди рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИ? рдЕрдЧрд░ рдРрд╕рд╛ рд╣реИ, рддреЛ рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЕрдЪреНрдЫрд╛ рд╡рд┐рдЪрд╛рд░ рд╣реИ!
рд▓реЗрдХрд┐рди рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рддрд░реНрдХреЛрдВ рдХреА рдЧрдгрдирд╛ рдХреЗ рдмрдЬрд╛рдп рд╡рд╕реНрддреБ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдмреЗрд╣рддрд░ рд╣реИ:

...
} else if (typeof this.scrollObservable === 'function') {
  scrollObservable = this.scrollObservable({
    image, 
    offset
  });
} else {
...

рд╕реНрдХреНрд░реЙрд▓рдСрдмреНрдЬрд░реНрд╡реЗрдмрд▓ рдХреЗ рд╡рд┐рдХрд▓реНрдк рдХреЗ рд░реВрдк рдореЗрдВ рдлрд╝рдВрдХреНрд╢рди рдкреНрд░рджрд╛рди рдХрд░реЗрдВ, рдЬреЛ рдСрдмреНрдЬрд░реНрд╡реЗрдмрд▓ рд▓реМрдЯрд╛рдПрдЧрд╛, рдЬреЛ рдЗрдореЗрдЬ рд▓реЛрдб рдЗрд╡реЗрдВрдЯ рдХреЛ рдЙрддреНрд╕рд░реНрдЬрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИ

рд╕рд╣реА рд╣реИ, рдореИрдВ scrollObservable рдХрд╛ рдирд╛рдо рдмрджрд▓рдирд╛ рднреА рдЪрд╛рд╣ рд╕рдХрддрд╛ рд╣реВрдВ рд▓реЗрдХрд┐рди рдпрд╣ рдПрдХ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдмрджрд▓рд╛рд╡ рд╣реЛрдЧрд╛ред

рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рддрд░реНрдХреЛрдВ рдХреА рдЧрдгрдирд╛ рдХреЗ рдмрдЬрд╛рдп рд╡рд╕реНрддреБ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдмреЗрд╣рддрд░ рд╣реИ

рдЗрд╕ рдмрд╛рдд рд╕реЗ рд╕рд╣рдордд!

рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдПрдХ рдЕрдЪреНрдЫрд╛ рд╡рд┐рдЪрд╛рд░ рд╣реИ, рдЦрд╛рд╕рдХрд░ рдПрдХ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдкрд░реНрдпрд╡реЗрдХреНрд╖рдХ рдкрд╛рд╕ рдХрд░рдирд╛ред

рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рддрд░реНрдХреЛрдВ рдХреА рдЧрдгрдирд╛ рдХреЗ рдмрдЬрд╛рдп рд╡рд╕реНрддреБ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдмреЗрд╣рддрд░ рд╣реИ

рдореИрдВ рднреА рдЗрд╕рд╕реЗ рд╕рд╣рдордд рд╣реВрдВред

#365 рдФрд░ рд╕рдВрд╕реНрдХрд░рдг 2.1.0 . рдореЗрдВ рдлрд┐рдХреНрд╕реНрдб

рдХреНрдпрд╛ рдпрд╣ рдкреГрд╖реНрда рдЙрдкрдпреЛрдЧреА рдерд╛?
0 / 5 - 0 рд░реЗрдЯрд┐рдВрдЧреНрд╕