-
Notifications
You must be signed in to change notification settings - Fork 143
/
lazyload-image.directive.ts
108 lines (100 loc) 路 3.84 KB
/
lazyload-image.directive.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import 'rxjs/add/operator/let';
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/operator/debounceTime';
import { Observable } from 'rxjs/Observable';
import { ReplaySubject } from 'rxjs/ReplaySubject';
import {
AfterContentInit,
Directive,
ElementRef,
EventEmitter,
Input,
NgZone,
Output,
OnChanges,
OnDestroy,
SimpleChanges
} from '@angular/core';
import { getScrollListener } from './scroll-listener';
import { lazyLoadImage } from './lazyload-image';
const windowTarget = typeof window !== 'undefined' ? window : undefined;
interface LazyLoadImageDirectiveProps {
lazyImage: string;
defaultImage: string;
errorImage: string;
scrollTarget: HTMLElement;
scrollObservable: Observable<Event>;
offset: number;
useSrcset: boolean;
}
@Directive({
selector: '[lazyLoad]'
})
export class LazyLoadImageDirective implements OnChanges, AfterContentInit, OnDestroy {
@Input('lazyLoad') lazyImage; // The image to be lazy loaded
@Input() defaultImage: string; // The image to be displayed before lazyImage is loaded
@Input() errorImage: string; // The image to be displayed if lazyImage load fails
@Input() scrollTarget: HTMLElement; // Scroll container that contains the image and emits scoll events
@Input() scrollObservable; // Pass your own scroll emitter
@Input() offset: number; // The number of px a image should be loaded before it is in view port
@Input() useSrcset: boolean; // Whether srcset attribute should be used instead of src
@Output() onLoad: EventEmitter<boolean> = new EventEmitter(); // Callback when an image is loaded
private propertyChanges$: ReplaySubject<LazyLoadImageDirectiveProps>;
private elementRef: ElementRef;
private ngZone: NgZone;
private platformId: string;
private scrollSubscription;
constructor(el: ElementRef, ngZone: NgZone) {
this.elementRef = el;
this.ngZone = ngZone;
this.propertyChanges$ = new ReplaySubject();
}
ngOnChanges(changes?: SimpleChanges) {
this.propertyChanges$.next({
lazyImage: this.lazyImage,
defaultImage: this.defaultImage,
errorImage: this.errorImage,
scrollTarget: this.scrollTarget,
scrollObservable: this.scrollObservable,
offset: this.offset | 0,
useSrcset: this.useSrcset
});
}
ngAfterContentInit() {
/**
* Disable lazy load image in server side
* @see https://github.com/tjoskar/ng-lazyload-image/issues/178
* @see https://github.com/tjoskar/ng-lazyload-image/issues/183
*/
if (typeof window === 'undefined') {
return null;
}
this.ngZone.runOutsideAngular(() => {
let scrollObservable: Observable<Event>;
if (this.scrollObservable) {
scrollObservable = this.scrollObservable.startWith('');
} else {
scrollObservable = getScrollListener(this.scrollTarget || windowTarget);
}
this.scrollSubscription = this.propertyChanges$
.debounceTime(10)
.switchMap(props => scrollObservable.let(
lazyLoadImage(
this.elementRef.nativeElement,
props.lazyImage,
props.defaultImage,
props.errorImage,
props.offset,
props.useSrcset,
props.scrollTarget
)
))
.subscribe(success => this.onLoad.emit(success));
});
}
ngOnDestroy() {
[this.scrollSubscription]
.filter(subscription => subscription && !subscription.isUnsubscribed)
.forEach(subscription => subscription.unsubscribe());
}
}