Angular 5:实现服务端加载Logo时加载动画淡出与图片淡入过渡
嘿,这个需求我之前做过几次,用Angular动画或者纯CSS都能搞定,下面给你分步拆解每个文件的修改:
实现步骤
1. 核心逻辑处理:Logotipo.component.ts
首先我们需要管理加载状态,重点注意:Blob下载完成不代表图片渲染完成,必须监听图片的onload事件再切换状态,避免出现空白闪烁问题:
import { Component, OnInit, OnDestroy } from '@angular/core'; // 如果选择Angular动画方案,需要导入以下动画API import { trigger, state, style, transition, animate } from '@angular/animations'; @Component({ selector: 'app-logotipo', templateUrl: './Logotipo.component.html', styleUrls: ['./Logotipo.component.css'], // Angular动画方案:添加动画配置 animations: [ // 加载动画的淡出过渡 trigger('spinnerFade', [ state('show', style({ opacity: 1, visibility: 'visible' })), state('hide', style({ opacity: 0, visibility: 'hidden' })), transition('show => hide', animate('300ms ease-out')) ]), // Logo图片的淡入过渡 trigger('logoFade', [ state('hidden', style({ opacity: 0 })), state('visible', style({ opacity: 1 })), transition('hidden => visible', animate('300ms ease-in')) ]) ] }) export class LogotipoComponent implements OnInit, OnDestroy { isLoading = true; logoUrl: string | null = null; private objectUrl: string | null = null; // 用于清理内存 ngOnInit(): void { this.loadLogoFromServer(); } private loadLogoFromServer(): void { // 替换成你从服务端获取Blob的实际逻辑(比如HttpClient请求) this.yourLogoService.getLogoBlob().subscribe(blob => { this.objectUrl = URL.createObjectURL(blob); const tempImg = new Image(); tempImg.src = this.objectUrl; // 监听图片渲染完成事件 tempImg.onload = () => { this.logoUrl = this.objectUrl; this.isLoading = false; }; // 处理加载失败的兜底逻辑 tempImg.onerror = () => { this.isLoading = false; console.error('Logo加载失败,请检查服务端返回'); }; }); } ngOnDestroy(): void { // 必须清理Object URL,防止内存泄漏 if (this.objectUrl) { URL.revokeObjectURL(this.objectUrl); } } }
2. 模板文件:Logotipo.component.html
提供两种方案,你可以根据项目复杂度选择:
方案A:Angular动画(灵活可控,适合复杂状态)
<div class="logo-container"> <!-- 加载动画 --> <div class="spinner" [@spinnerFade]="isLoading ? 'show' : 'hide'"> <div class="spinner-circle"></div> </div> <!-- Logo图片 --> <img *ngIf="logoUrl" [src]="logoUrl" alt="品牌Logo" class="logo-image" [@logoFade]="isLoading ? 'hidden' : 'visible'" /> </div>
方案B:纯CSS过渡(简单轻量,无需额外模块)
<div class="logo-container" [class.is-loading]="isLoading"> <!-- 加载动画 --> <div class="spinner"> <div class="spinner-circle"></div> </div> <!-- Logo图片 --> <img *ngIf="logoUrl" [src]="logoUrl" alt="品牌Logo" class="logo-image" /> </div>
3. 样式文件:Logotipo.component.css(必加)
不管用哪种方案,都需要基础样式实现定位和过渡效果:
.logo-container { position: relative; width: 160px; /* 替换成你的Logo实际尺寸 */ height: 60px; } .spinner, .logo-image { position: absolute; top: 0; left: 0; width: 100%; height: 100%; transition: opacity 0.3s ease, visibility 0.3s ease; } /* 方案B专属:状态切换样式 */ .logo-container.is-loading .spinner { opacity: 1; visibility: visible; } .logo-container.is-loading .logo-image { opacity: 0; visibility: hidden; } .logo-container:not(.is-loading) .spinner { opacity: 0; visibility: hidden; } .logo-container:not(.is-loading) .logo-image { opacity: 1; visibility: visible; } /* 加载动画样式(旋转圆圈) */ .spinner-circle { width: 32px; height: 32px; border: 3px solid #eee; border-top: 3px solid #2563eb; border-radius: 50%; animation: spin 1s linear infinite; margin: 14px auto 0; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
4. 关于app.component.ts/app.module.ts
如果选择方案A(Angular动画),需要在根模块(比如AppModule)中导入动画模块:
// app.module.ts import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; @NgModule({ imports: [ // ...其他已导入模块 BrowserAnimationsModule ] }) export class AppModule { }
app.component.ts本身无需修改,只要在模板中正常调用<app-logotipo></app-logotipo>即可。
关键注意点:
- 绝不可以在Blob下载完成后直接切换状态,必须等图片
onload触发,否则会出现图片未渲染就隐藏加载动画的空白问题。 - 一定要在组件销毁时清理
Object URL,避免浏览器内存泄漏。 - 可以调整
0.3s的过渡时间来控制动画快慢,匹配你的产品风格。
内容的提问来源于stack exchange,提问作者Javier Torron Diaz
相关产品推荐
相关产品推荐

