TC *_*rts 11 typescript ionic-framework ionic2 ionic3 angular
美好的一天,
我正在研究Ionic应用程序,我正在从JSON提要中动态加载图像.我希望当从外部URL拉入图像时,占位符图像显示在其位置,此后,占位符图像应该在加载后由"真实"图像替换.
我目前的情况的一个例子是:
<ion-card *ngFor="let item of items"...
<img [src]="item.picture" />
Run Code Online (Sandbox Code Playgroud)
感谢和问候.
seb*_*ras 20
大多数答案都是关于在同一视图中添加加载的检查的逻辑,但似乎不合适.相反,您可以创建自己的指令来处理它.您可以查看这篇精彩的文章,看看它是如何完成的.
首先将此GIF复制到您的src/assets文件夹中,然后为其命名preloader.gif.
然后添加此自定义指令.代码几乎是不言自明的:
// An image directive based on http://blog.teamtreehouse.com/learn-asynchronous-image-loading-javascript
import {Directive, Input, OnInit} from '@angular/core';
// Define the Directive meta data
@Directive({
selector: '[img-preloader]', //E.g <img mg-img-preloader="http://some_remote_image_url"
host: {
'[attr.src]': 'finalImage' //the attribute of the host element we want to update. in this case, <img 'src' />
}
})
//Class must implement OnInit for @Input()
export class ImagePreloader implements OnInit {
@Input('img-preloader') targetSource: string;
downloadingImage : any; // In class holder of remote image
finalImage: any; //property bound to our host attribute.
// Set an input so the directive can set a default image.
@Input() defaultImage : string = 'assets/preloader.gif';
//ngOnInit is needed to access the @inputs() variables. these aren't available on constructor()
ngOnInit() {
//First set the final image to some default image while we prepare our preloader:
this.finalImage = this.defaultImage;
this.downloadingImage = new Image(); // create image object
this.downloadingImage.onload = () => { //Once image is completed, console.log confirmation and switch our host attribute
console.log('image downloaded');
this.finalImage = this.targetSource; //do the switch
}
// Assign the src to that of some_remote_image_url. Since its an Image Object the
// on assignment from this.targetSource download would start immediately in the background
// and trigger the onload()
this.downloadingImage.src = this.targetSource;
}
}
Run Code Online (Sandbox Code Playgroud)
然后将新指令添加到您的app模块,如下所示:
import { NgModule, ErrorHandler } from '@angular/core';
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
import { MyApp } from './app.component';
import { ImagePreloader } from '../components/img-preload/img-preload';
@NgModule({
declarations: [
MyApp,
ImagePreloader, // <------- Here!
// ...
],
imports: [
IonicModule.forRoot(MyApp)
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
// ...
],
providers: [{provide: ErrorHandler, useClass: IonicErrorHandler}]
})
export class AppModule {}
Run Code Online (Sandbox Code Playgroud)
这是您使用新的自定义指令的方法:
<img img-preloader="https://images.unsplash.com/photo-1413781892741-08a142b23dfe" alt="">
Run Code Online (Sandbox Code Playgroud)
这就是它的样子:
然后,您可以设置图像容器的高度/宽度,因此预加载器gif和最终图像都具有相同的尺寸.
您可以修改 JSON 以具有loaded布尔属性吗?如果可以的话,这会很容易,请按照以下步骤操作:
<ion-card *ngFor="let item of items">
<img [src]="item.picture" (load)="item.loaded = true" [hidden]="!item.loaded" />
<img src="../path/to/your/placeholer/image.jpg" [hidden]="item.loaded">
</ion-card>
Run Code Online (Sandbox Code Playgroud)
您将有一个加载属性始终初始化为false,当图像加载时,(load)将触发事件并将图像加载属性更改为 true,隐藏占位符图像并显示加载的图像。
如果您无法更改此 JSON(或者它太大而无法编辑),您可以使用上面的代码,但在您的页面中执行以下操作.ts
public functionWhoseIsLoadingYourJson(){
// HTTP REQUEST FOR JSON
.subscribe(response => {
response.forEach(element => {
element.loaded = false;
});
this.items = response;
});
}
Run Code Online (Sandbox Code Playgroud)
只需迭代您的响应,并在每个对象中将已加载的属性设置为 false。如果这引发一些错误,你可以将你的内容放在<ion-card>一个带有 *ngIf 的 div 中
<div *ngIf="this.items != null">
<!-- ion card -->
</div>
Run Code Online (Sandbox Code Playgroud)
由于它来自 Firebase,因此可以使用三个选项来更新 JSON。第一个是一个函数,您只需执行一次即可更新数据库,第二个仍然是我给出的代码(迭代结果并推送布尔值),但由于您使用的是 Firebase,所以它会有所不同。
第一个解决方案:
在代码中的某个位置,它可以是任何页面,您只需执行一次:
firebase.database().ref('myDataNode').on('value', snapshot => {
for(let key in snapshot.val()){
firebase.database().ref('myDataNode/' + key + '/loaded').set(false);
}
});
Run Code Online (Sandbox Code Playgroud)
请注意,我正在循环遍历您的所有结果myDataNode,并使用它们的密钥将loaded属性设置为false. 但使用时要小心,set因为您可以覆盖所有节点,因此在执行此方法之前请记住导出您的 Firebase 节点以进行备份。如果您从代码中的任何位置将图像推送到 Firebase,请记住更改它以loaded一起设置属性。
正如前面提到的,第二个是我在这个答案中所做的,但现在在 Firebase 调用中使用它并使用快照附带的 forEach 方法:
firebase.database().ref('myDataNode').on('value', snapshot => {
snapshot.forEach(element =>{
this.myDataNode.push({
picture: element.val(), // maybe it needs to be element.val().nameOfYourProperty
loaded: false
})
});
});
Run Code Online (Sandbox Code Playgroud)
这会将带有图片 url 和已加载属性的新元素推送到数组中。如果它无法识别该.push()方法,只需将变量声明为数组:
public myDataNode: any[];
Run Code Online (Sandbox Code Playgroud)
第三个只是在本地更新,迭代您的 firebase 快照,将结果保存在本地变量中,创建一个新属性并将其推送到您的数组:
firebase.database().ref('myDataNode').on('value', snapshot => {
for (let key in snapshot.val()){
snapshot.forEach(item => { // iterate snapshot
let record = item.val(); // save the snapshot item value in a local variable
record.loaded = true; // add the property
this.newArray.push(record); // push it to your array that'll be used in ng-for
return true; // return true to foreach
});
}
});
Run Code Online (Sandbox Code Playgroud)
希望这可以帮助。
| 归档时间: |
|
| 查看次数: |
7908 次 |
| 最近记录: |