Angular 2 - 预加载背景图片?

时间:2016-09-23 08:38:51

标签: javascript angular

我有这个角度项目,我有一个填充页面的大背景图像和一个带有链接的简单侧边栏,点击后,将使用另一个图像(来自cdn)更改背景的URL。由于这些图像相当大,它们需要一两秒才能加载并且它很明显,我想添加预加载器,但我不确定如何在角度2中完成。

在我的HTML中,我有这个:

<section class="fullsizebg image-bg" [ngStyle]="{'background-image': 'url(' + urlImage + ')'}"></section>

变量urlImage填充在组件的构造函数中,侧栏链接在单击时更改了它的值,使用如下的简单函数:

generateImage(data: any){
    this.urlImage = 'http://example.com/mycdn/'+this.data.url+'.jpg';
}

因此,网址实际上已立即更改,但图片需要加载一些。我想添加一个加载gif或类似的东西,以保持图像更改为用户平滑,而不是像现在一样跳跃。

5 个答案:

答案 0 :(得分:14)

一种方法是使用Blob获取图像并将其存储在img组件中,这样您就可以完成加载过程,并可以添加加载的gif :

@Component({
   selector:'loading-image',
   template:'<img alt="foo" [src]="src"/>'
})
export class ExampleLoadingImage{

   public src:string = "http://example.com/yourInitialImage.png";

   constructor(private http:Http){}

   generateImage(data: any): void {
      this.src = 'http://www.downgraf.com/wp-content/uploads/2014/09/01-progress.gif'; //Just a random loading gif found on google.
      this.http.get('http://example.com/mycdn/'+this.data.url+'.jpg')
         .subscribe(response => {
            let urlCreator = window.URL;
            this.src = urlCreator.createObjectURL(response.blob());
         });
    }
}

NB :您应该键入数据参数,键入是确保代码一致性的好方法,any只应该用作小丑,例如ObjectJava

答案 1 :(得分:8)

此解决方案利用了角度和浏览器已经提供的角度。图像加载由浏览器完成,无需自己处理任何数据或DOM。

我已经在Chrome 53上对此进行了测试,并且它运行良好。

这是你的元素,它的背景发生了变化:

<div class="yourBackgroundClass" [style.background-image]="'url(' + imgUrl + ')'"></div>

要预取图像,我们使用未显示的图像标记。最好另外制作position: absolute并将其移出视图或使其非常小,这样它就不会干扰您的实际内容。

<img [src]="imgPreloadUrl" (load)="imgUrl = imgPreloadUrl" hidden>

通过设置imgPreloadUrlimg&#39; src会按角度更新,浏览器会将图片加载到不可见的img标记中。完成后,onload会触发,我们会设置imgUrl = imgPreloadUrl。 Angular现在更新实际背景的style.background-image,并且背景图像立即切换,因为它已经加载到隐藏图像中。

虽然imgUrl !== imgPreloadUrl我们可以显示一个微调器来指示加载:

<div class="spinner" *ngIf="imgUrl !== imgPreloadUrl"></div>

测试:

<button (click)="imgPreloadUrl = 'https://upload.wikimedia.org/wikipedia/commons/2/24/Willaerts_Adam_The_Embarkation_of_the_Elector_Palantine_Oil_Canvas-huge.jpg'">test</button>

答案 2 :(得分:7)

使用图片对象Plunker Demo

tmpImg: HTMLImageElement; // will be used to load the actual image before showing it

generateImage(data: any){
 this.urlImage = 'http://example.com/mycdn/'+ 'loading_GIF_url';  // show loading gif

 let loaded = () => { // wait for image to load then replace it with loadingGIF
   this.urlImage = 'http://example.com/mycdn/' + this.data.url+'.jpg';
 }

 // background loading logic
 if(this.tmpImg){
   this.tmpImg.onload = null; // remove the previous onload event, if registered
 }
 this.tmpImg = new Image();
 this.tmpImg.onload = loaded;  // register the onload event
 this.tmpImg.src = 'http://example.com/mycdn/'+this.data.url+'.jpg';
}

答案 3 :(得分:1)

您需要的东西很少,例如http,解析器和消毒剂。这是link的解释,它是如何从头开始实现的。

例如,您有一个请求,然后将返回的Blob转换为安全样式,以便我们能够在样式指令中使用它

this.http.get('assets/img/bg.jpg', { responseType: 'blob' }).pipe(
  map( image => {
    const blob: Blob = new Blob([image], { type: 'image/jpeg' });
    const imageStyle = `url(${window.URL.createObjectURL(blob)})`;
    return this.sanitizer.bypassSecurityTrustStyle(imageStyle);
  })
)

答案 4 :(得分:0)

我最近将其实现为structural directive

import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';

@Directive({ selector: '[appPreloadImage]'})
export class PreloadImageDirective {

  @Input("appPreloadImage") imageUrl : string;

  constructor( private templateRef : TemplateRef<any>,
               private viewContainer : ViewContainerRef) {
  }

  private showView() {
    this.viewContainer.createEmbeddedView(this.templateRef);
  }

  ngOnInit() {
    var self = this;
    self.viewContainer.clear();
    var tmpImg = new Image();
    tmpImg.src = self.imageUrl;
    tmpImg.onload = function() {
        self.showView();
    }
    tmpImg.onerror = function() {
        self.showView();
    }
  }
}

您可以像这样使用它:

<div *appPreloadImage="'/url/of/preloaded/image.jpg'">
  <!-- Nothing in here will be displayed until the 
       request to the URL above has been completed 
      (even if that request fails) -->
</div>

(请注意,单引号嵌套在双引号内-这是因为我们要传递字符串文字。)