diff --git a/components/image/doc/index.en-US.md b/components/image/doc/index.en-US.md index f8dd1da3bcb..88fbfb2d1d8 100644 --- a/components/image/doc/index.en-US.md +++ b/components/image/doc/index.en-US.md @@ -29,6 +29,7 @@ import { NzImageModule } from 'ng-zorro-antd/image'; | nzCloseOnNavigation | Whether to close the image preview when the user goes backwards/forwards in history. Note that this usually doesn't include clicking on links (unless the user is using the HashLocationStrategy). | `boolean` | `false` | ✅ | | nzDirection | Text directionality | `Direction` | `'ltr'` | ✅ | | nzScaleStep | `1 + nzScaleStep` is the step to increase or decrease the scale | `number` | 0.5 | ✅ | +| nzLoading | Image element's loading property. reference [loading property](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/loading) | `eager \| lazy` | `eager` | - | Other attributes [](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#Attributes) diff --git a/components/image/doc/index.zh-CN.md b/components/image/doc/index.zh-CN.md index 9723a1823f3..f6080e7a975 100644 --- a/components/image/doc/index.zh-CN.md +++ b/components/image/doc/index.zh-CN.md @@ -30,6 +30,7 @@ import { NzImageModule } from 'ng-zorro-antd/image'; | nzCloseOnNavigation | 当用户在历史中前进/后退时是否关闭预览。注意,这通常不包括点击链接(除非用户使用 HashLocationStrategy)。 | `boolean` | `false` | ✅ | | nzDirection | 文字方向 | `Direction` | `'ltr'` | ✅ | | nzScaleStep | `1 + nzScaleStep` 为缩放放大的每步倍数 | `number` | 0.5 | ✅ | +| nzLoading | 图片元素的加载属性。 参见 [HTMLImageElement.loading](https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLImageElement/loading) | `eager \| lazy` | `eager` | - | 其他属性见 [](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#Attributes) diff --git a/components/image/image.directive.ts b/components/image/image.directive.ts index 216886fb6a8..228c4a254a3 100644 --- a/components/image/image.directive.ts +++ b/components/image/image.directive.ts @@ -29,6 +29,7 @@ import { NZ_DEFAULT_SCALE_STEP } from './image-preview.component'; import { NzImageService } from './image.service'; const NZ_CONFIG_MODULE_NAME: NzConfigKey = 'image'; +const INTERSECTION_THRESHOLD = 0.1; export type ImageStatusType = 'error' | 'loading' | 'normal'; export type NzImageUrl = string; @@ -47,6 +48,7 @@ export class NzImageDirective implements OnInit, OnChanges, OnDestroy { @Input() nzSrc = ''; @Input() nzSrcset = ''; + @Input() nzLoading: 'eager' | 'lazy' = 'eager'; @Input({ transform: booleanAttribute }) @WithConfig() nzDisablePreview: boolean = false; @Input() @WithConfig() nzFallback: string | null = null; @Input() @WithConfig() nzPlaceholder: string | null = null; @@ -133,7 +135,9 @@ export class NzImageDirective implements OnInit, OnChanges, OnDestroy { ngOnChanges(changes: SimpleChanges): void { const { nzSrc } = changes; if (nzSrc) { - this.getElement().nativeElement.src = nzSrc.currentValue; + if (this.nzLoading === 'eager') { + this.getElement().nativeElement.src = nzSrc.currentValue; + } this.backLoad(); } } @@ -145,18 +149,35 @@ export class NzImageDirective implements OnInit, OnChanges, OnDestroy { */ private backLoad(): void { this.backLoadImage = this.document.createElement('img'); - this.backLoadImage.src = this.nzSrc; - this.backLoadImage.srcset = this.nzSrcset; + + if (this.nzLoading === 'eager') { + this.backLoadImage.src = this.nzSrc; + this.backLoadImage.srcset = this.nzSrcset; + } this.status = 'loading'; // unsubscribe last backLoad this.backLoadDestroy$.next(); this.backLoadDestroy$.complete(); this.backLoadDestroy$ = new Subject(); + if (this.backLoadImage.complete) { - this.status = 'normal'; - this.getElement().nativeElement.src = this.nzSrc; - this.getElement().nativeElement.srcset = this.nzSrcset; + if (this.nzLoading === 'lazy') { + const observer = new IntersectionObserver( + entries => { + entries.forEach(entry => { + if (entry.isIntersecting) { + this.backLoadCompleteStateHandler(); + observer.disconnect(); + } + }); + }, + { threshold: INTERSECTION_THRESHOLD } + ); + observer.observe(this.getElement().nativeElement); + } else { + this.backLoadCompleteStateHandler(); + } } else { if (this.nzPlaceholder) { this.getElement().nativeElement.src = this.nzPlaceholder; @@ -187,4 +208,10 @@ export class NzImageDirective implements OnInit, OnChanges, OnDestroy { }); } } + + private backLoadCompleteStateHandler(): void { + this.status = 'normal'; + this.getElement().nativeElement.src = this.nzSrc; + this.getElement().nativeElement.srcset = this.nzSrcset; + } } diff --git a/components/image/image.spec.ts b/components/image/image.spec.ts index 0fde131f1f6..93c70ac05b3 100644 --- a/components/image/image.spec.ts +++ b/components/image/image.spec.ts @@ -110,6 +110,13 @@ describe('Basics', () => { fixture.detectChanges(); expect(image.src).toBe(SECOND_SRC); })); + + it('should the loading attribute be auto at default', fakeAsync(() => { + const image = debugElement.nativeElement.querySelector('img'); + context.nzImage.backLoadImage.dispatchEvent(new Event('load')); + fixture.detectChanges(); + expect(image.loading).toBe('auto'); + })); }); describe('Placeholder', () => { @@ -715,12 +722,13 @@ describe('Preview', () => { }); @Component({ - template: ` ` + template: ` ` }) export class TestImageBasicsComponent { @ViewChild(NzImageDirective) nzImage!: NzImageDirective; src = ''; placeholder: string | null = ''; + loading: 'eager' | 'lazy' = 'eager'; } @Component({