mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
docs(img): ion-img docs
This commit is contained in:
@@ -8,7 +8,89 @@ import { Platform } from '../../platform/platform';
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @name Img
|
||||
* @description
|
||||
* Two of the biggest cuprits of scrolling jank is starting up a new
|
||||
* HTTP request, and rendering images. These two reasons is largely why
|
||||
* `ion-img` was created and the problems which it is helping to solve.
|
||||
* The standard `<img>` element is often a large source of these problems,
|
||||
* and what makes matters worse is that the app does not have fine-grained
|
||||
* control of each img element.
|
||||
*
|
||||
* The `ion-img` component is similar to the standard `<img>` element,
|
||||
* but it also adds features in order to provide improved performance.
|
||||
* Features include only loading images which are visible, using web workers
|
||||
* for HTTP requests, preventing jank while scrolling and in-memory caching.
|
||||
*
|
||||
* Note that `ion-img` also comes with a few more restrictions in comparison to
|
||||
* the standard `<img>` element. A good rule is, if there are only a few images
|
||||
* to be rendered on one page, then the standard `<img>` may be best. However, if
|
||||
* a page has the potential for hundreds or even thousands of images within a
|
||||
* scrollable area, then `ion-img` would be better suited for the job.
|
||||
*
|
||||
*
|
||||
* ### Lazy Loading
|
||||
*
|
||||
* Lazy loading images refers to only loading images which are actually
|
||||
* visible within the user's viewport. This also means that images which are
|
||||
* not viewable on the initial load would not be downloaded. Next, as the user
|
||||
* scrolls down, each image which becomes visible is then loaded on-demand.
|
||||
*
|
||||
* The benefits of this approach is that unnecessary HTTP requests are not
|
||||
* started and valuable bandwidth wasted, and to free up browser resources
|
||||
* which would be wasted on images which are not even viewable. For example,
|
||||
* animated GIFs are enourmous performance drains, however, with `ion-img`
|
||||
* the app is able to dedicate resources to just the viewable images.
|
||||
*
|
||||
*
|
||||
* ### Image Dimensions
|
||||
*
|
||||
* By providing image dimensions up front, Ionic is able to accurately size
|
||||
* up the image's location within the viewport, which helps lazy load only
|
||||
* images which are viewable. Image dimensions can either by set as properties,
|
||||
* inline styles, or stylesheets. It doesn't matter which method of setting
|
||||
* dimensions is used, but it's important that somehow each `ion-img`
|
||||
* has been given an exact size.
|
||||
*
|
||||
* For example, by default `<ion-avatar>` and `<ion-thumbnail>` already come
|
||||
* with exact sizes when placed within `<ion-item>`. By giving each image an
|
||||
* exact size, this then further locks in the size of each `ion-item`, which
|
||||
* again helps improve scroll performance.
|
||||
*
|
||||
* @usage
|
||||
* ```html
|
||||
* <!-- set using plain attributes -->
|
||||
* <ion-img width="80" height="80" src="..."></ion-img>
|
||||
*
|
||||
* <!-- bind using properties -->
|
||||
* <ion-img [width]="imgWidth" [height]="imgHeight" src="..."></ion-img>
|
||||
*
|
||||
* <!-- inline styles -->
|
||||
* <ion-img style="width: 80px; height: 80px;" src="..."></ion-img>
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* ### Web Worker and XHR Requests
|
||||
*
|
||||
* Another big cause of scroll jank is kicking off a new HTTP request, which
|
||||
* is exactly what images do. Normally, this isn't a problem for something like
|
||||
* a blog since all image HTTP requests are started immediately as HTML
|
||||
* parses. However, Ionic has the ability to include hundreds to thousands of
|
||||
* images within one page, but we're not actually loading all of the images at once.
|
||||
*
|
||||
* Imagine an app where users can slowly, or quickly, scroll through hundreds of
|
||||
* images. If they're scrolling extremely fast, the app wouldn't want to start all of
|
||||
* those requests, but if they're scrolling slowly they would. Additionally, it's
|
||||
* most browsers can only have six requests at one time for the same domain, so
|
||||
* it's extemely important that we're managing which images we should downloading.
|
||||
*
|
||||
* By place XMLHttpRequest within a web worker, we're able to pass off the heavy
|
||||
* lifting to another thread. Not only are able to take the load of the main thread,
|
||||
* but we're also able to accurately control exactly which images should be
|
||||
* downloading, along with the ability to abort unnecessary requests. Aborting
|
||||
* requets is just as important so that Ionic can free up connections for the most
|
||||
* important images which are visible.
|
||||
*
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ion-img',
|
||||
@@ -28,10 +110,6 @@ export class Img implements OnDestroy {
|
||||
/** @internal */
|
||||
_cache: boolean = true;
|
||||
/** @internal */
|
||||
_lazy: boolean = true;
|
||||
/** @internal */
|
||||
_ww: boolean = true;
|
||||
/** @internal */
|
||||
_cb: Function;
|
||||
/** @internal */
|
||||
_bounds: any;
|
||||
@@ -69,6 +147,9 @@ export class Img implements OnDestroy {
|
||||
this._isLoaded(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @input {string} Image src.
|
||||
*/
|
||||
@Input()
|
||||
get src(): string {
|
||||
return this._src;
|
||||
@@ -87,6 +168,9 @@ export class Img implements OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
reset() {
|
||||
if (this._requestingSrc) {
|
||||
// abort any active requests
|
||||
@@ -102,6 +186,9 @@ export class Img implements OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
update() {
|
||||
if (this._src && this._content.isImgsRefreshable()) {
|
||||
if (this.canRequest && (this._src !== this._renderedSrc && this._src !== this._requestingSrc) && !this._tmpDataUri) {
|
||||
@@ -132,10 +219,7 @@ export class Img implements OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
_loadResponse(msg: ImgResponseMessage) {
|
||||
private _loadResponse(msg: ImgResponseMessage) {
|
||||
this._requestingSrc = null;
|
||||
|
||||
if (msg.status === 200) {
|
||||
@@ -201,6 +285,11 @@ export class Img implements OnDestroy {
|
||||
return this._rect;
|
||||
}
|
||||
|
||||
/**
|
||||
* @input {any} Sets the bounding rectangle of the element relative to the viewport.
|
||||
* When using `VirtualScroll`, each virtual item should pass its bounds to each
|
||||
* `ion-img`.
|
||||
*/
|
||||
@Input()
|
||||
set bounds(b: any) {
|
||||
if (isPresent(b)) {
|
||||
@@ -208,22 +297,12 @@ export class Img implements OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
@Input()
|
||||
get lazyLoad(): boolean {
|
||||
return this._lazy;
|
||||
}
|
||||
set lazyLoad(val: boolean) {
|
||||
this._lazy = isTrueProperty(val);
|
||||
}
|
||||
|
||||
@Input()
|
||||
get webWorker(): boolean {
|
||||
return this._ww;
|
||||
}
|
||||
set webWorker(val: boolean) {
|
||||
this._ww = isTrueProperty(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* @input {boolean} After an image has been successfully downloaded, it can be cached
|
||||
* in-memory. This is useful for `VirtualScroll` by allowing image responses to be
|
||||
* cached, and not rendered, until after scrolling has completed, which allows for
|
||||
* smoother scrolling.
|
||||
*/
|
||||
@Input()
|
||||
get cache(): boolean {
|
||||
return this._cache;
|
||||
@@ -232,19 +311,27 @@ export class Img implements OnDestroy {
|
||||
this._cache = isTrueProperty(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* @input {string} Image width. If this property is not set it's important that
|
||||
* the dimensions are still set using CSS.
|
||||
*/
|
||||
@Input()
|
||||
set width(val: string | number) {
|
||||
this._wQ = getUnitValue(val);
|
||||
this._setDims();
|
||||
}
|
||||
|
||||
/**
|
||||
* @input {string} Image height. If this property is not set it's important that
|
||||
* the dimensions are still set using CSS.
|
||||
*/
|
||||
@Input()
|
||||
set height(val: string | number) {
|
||||
this._hQ = getUnitValue(val);
|
||||
this._setDims();
|
||||
}
|
||||
|
||||
_setDims() {
|
||||
private _setDims() {
|
||||
if (this.canRender && (this._w !== this._wQ || this._h !== this._hQ)) {
|
||||
var wrapperEle: HTMLImageElement = this._elementRef.nativeElement;
|
||||
var renderer = this._renderer;
|
||||
@@ -263,7 +350,8 @@ export class Img implements OnDestroy {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the `alt` attribute on the inner `img` element.
|
||||
* @input {string} Set the `alt` attribute which gets assigned to
|
||||
* the inner `img` element.
|
||||
*/
|
||||
@Input() alt: string = '';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user