mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-20 12:29:55 +08:00
perf(img): do not reuse img elements
Safari UIWebView has troubles dropping image requests when the src changes, and when there are hundreds going in and out this causes issues. Instead, do not reuse img elements. Closes #6112
This commit is contained in:
@ -7,6 +7,7 @@ export * from './components/button/button'
|
||||
export * from './components/checkbox/checkbox'
|
||||
export * from './components/content/content'
|
||||
export * from './components/icon/icon'
|
||||
export * from './components/img/img'
|
||||
export * from './components/infinite-scroll/infinite-scroll'
|
||||
export * from './components/infinite-scroll/infinite-scroll-content'
|
||||
export * from './components/input/input'
|
||||
|
@ -1,5 +1,6 @@
|
||||
import {Component, Input, HostBinding, ViewChild, ElementRef, ViewEncapsulation} from 'angular2/core';
|
||||
import {Component, Input, ElementRef, ChangeDetectionStrategy, ViewEncapsulation, NgZone} from 'angular2/core';
|
||||
|
||||
import {raf} from '../../util/dom';
|
||||
import {isPresent} from '../../util/util';
|
||||
import {Platform} from '../../platform/platform';
|
||||
|
||||
@ -7,50 +8,85 @@ import {Platform} from '../../platform/platform';
|
||||
@Component({
|
||||
selector: 'ion-img',
|
||||
template:
|
||||
'<div *ngIf="_useA" class="img-placeholder" [style.height]="_h" [style.width]="_w"></div>' +
|
||||
'<img #imgA *ngIf="_useA" (load)="_onLoad()" [src]="_srcA" [style.height]="_h" [style.width]="_w">' +
|
||||
'<div *ngIf="!_useA" class="img-placeholder" [style.height]="_h" [style.width]="_w"></div>' +
|
||||
'<img #imgB *ngIf="!_useA" (load)="_onLoad()" [src]="_srcB" [style.height]="_h" [style.width]="_w">',
|
||||
'<div class="img-placeholder" [style.height]="_h" [style.width]="_w"></div>',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
})
|
||||
export class Img {
|
||||
private _src: string = '';
|
||||
private _srcA: string = '';
|
||||
private _srcB: string = '';
|
||||
private _useA: boolean = true;
|
||||
private _normalizeSrc: string = '';
|
||||
private _imgs: HTMLImageElement[] = [];
|
||||
private _w: string;
|
||||
private _h: string;
|
||||
private _enabled: boolean = true;
|
||||
|
||||
constructor(private _elementRef: ElementRef, private _platform: Platform) {}
|
||||
|
||||
@ViewChild('imgA') private _imgA: ElementRef;
|
||||
@ViewChild('imgB') private _imgB: ElementRef;
|
||||
constructor(private _elementRef: ElementRef, private _platform: Platform, private _zone: NgZone) {}
|
||||
|
||||
@Input()
|
||||
set src(val: string) {
|
||||
val = (isPresent(val) ? val : '');
|
||||
let tmpImg = new Image();
|
||||
tmpImg.src = isPresent(val) ? val : '';
|
||||
|
||||
if (this._src !== val) {
|
||||
this._src = val;
|
||||
this._loaded = false;
|
||||
this._srcA = this._srcB = '';
|
||||
this._useA = !this._useA;
|
||||
this._update();
|
||||
}
|
||||
this._src = isPresent(val) ? val : '';
|
||||
this._normalizeSrc = tmpImg.src;
|
||||
|
||||
this._update();
|
||||
}
|
||||
|
||||
private _update() {
|
||||
if (this._enabled && this.isVisible()) {
|
||||
if (this._useA) {
|
||||
this._srcA = this._src;
|
||||
if (this._enabled && this._src !== '' && this.isVisible()) {
|
||||
// actively update the image
|
||||
|
||||
} else {
|
||||
this._srcB = this._src;
|
||||
for (var i = this._imgs.length - 1; i >= 0; i--) {
|
||||
if (this._imgs[i].src === this._normalizeSrc) {
|
||||
// this is the active image
|
||||
if (this._imgs[i].complete) {
|
||||
this._loaded(true);
|
||||
}
|
||||
|
||||
} else {
|
||||
// no longer the active image
|
||||
if (this._imgs[i].parentElement) {
|
||||
this._imgs[i].parentElement.removeChild(this._imgs[i]);
|
||||
}
|
||||
this._imgs.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!this._imgs.length) {
|
||||
this._zone.runOutsideAngular(() => {
|
||||
let img = new Image();
|
||||
img.style.width = this._w;
|
||||
img.style.height = this._h;
|
||||
|
||||
img.addEventListener('load', () => {
|
||||
if (img.src === this._normalizeSrc) {
|
||||
this._elementRef.nativeElement.appendChild(img);
|
||||
raf(() => {
|
||||
this._update();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
img.src = this._src;
|
||||
|
||||
this._imgs.push(img);
|
||||
this._loaded(false);
|
||||
});
|
||||
}
|
||||
|
||||
} else {
|
||||
// do not actively update the image
|
||||
if (!this._imgs.some(img => img.src === this._normalizeSrc)) {
|
||||
this._loaded(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _loaded(isLoaded: boolean) {
|
||||
this._elementRef.nativeElement.classList[isLoaded ? 'add': 'remove']('img-loaded');
|
||||
}
|
||||
|
||||
enable(shouldEnable: boolean) {
|
||||
this._enabled = shouldEnable;
|
||||
this._update();
|
||||
@ -61,26 +97,6 @@ export class Img {
|
||||
return bounds.bottom > 0 && bounds.top < this._platform.height();
|
||||
}
|
||||
|
||||
@HostBinding('class.img-loaded')
|
||||
private _loaded: boolean = false;
|
||||
|
||||
private _onLoad() {
|
||||
this._loaded = this.isLoaded();
|
||||
}
|
||||
|
||||
isLoaded() {
|
||||
let imgEle: HTMLImageElement;
|
||||
|
||||
if (this._useA && this._imgA) {
|
||||
imgEle = this._imgA.nativeElement;
|
||||
|
||||
} else if (this._imgB) {
|
||||
imgEle = this._imgB.nativeElement;
|
||||
|
||||
}
|
||||
return (imgEle && imgEle.src !== '' && imgEle.complete);
|
||||
}
|
||||
|
||||
@Input()
|
||||
set width(val: string | number) {
|
||||
this._w = (typeof val === 'number') ? val + 'px' : val;
|
||||
|
Reference in New Issue
Block a user