Flutter中如何为网络图片添加加载占位符或动画?
解决图片加载时显示占位内容的方案
核心逻辑
不管使用哪种技术栈,核心思路都是:
- 初始状态下显示占位加载器/动画
- 监听图片的加载完成(或失败)事件,完成后替换占位内容
原生JavaScript实现
<!-- HTML结构 --> <div class="image-container"> <div class="loader">加载中...</div> </div> <style> .image-container { width: 100%; height: 200px; /* 与图片预期高度保持一致 */ } .loader { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; background: #f5f5f5; border-radius: 4px; } </style> <script> const container = document.querySelector('.image-container'); const img = new Image(); img.src = 'https://example.com/your-image.jpg'; // 加载完成后替换占位内容 img.onload = function() { container.innerHTML = ''; container.appendChild(img); }; // 加载失败时显示错误提示 img.onerror = function() { container.innerHTML = '<div style="color:#c62828;">图片加载失败</div>'; }; </script>
React函数组件实现
import { useState } from 'react'; function NetworkImage({ src, alt }) { const [isLoading, setIsLoading] = useState(true); const [hasError, setHasError] = useState(false); return ( <div className="image-wrapper"> {/* 加载中显示动画占位 */} {isLoading && ( <div className="loader"> <div className="spinner"></div> </div> )} {/* 加载失败显示错误 */} {hasError && <div className="error">图片加载失败</div>} {/* 加载完成显示图片 */} {!isLoading && !hasError && ( <img src={src} alt={alt} onLoad={() => setIsLoading(false)} onError={() => { setIsLoading(false); setHasError(true); }} style={{ display: isLoading ? 'none' : 'block', width: '100%' }} /> )} </div> ); } // 配套CSS /* .image-wrapper { position: relative; width: 100%; height: 200px; } .loader { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: #f5f5f5; display: flex; align-items: center; justify-content: center; } .spinner { width: 30px; height: 30px; border: 3px solid #ccc; border-top-color: #007bff; border-radius: 50%; animation: spin 1s linear infinite; } @keyframes spin { to { transform: rotate(360deg); } } .error { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; background: #ffebee; color: #c62828; } */
Vue3组件实现
<template> <div class="image-container"> <div v-if="isLoading" class="loader"> <div class="spinner"></div> </div> <div v-else-if="hasError" class="error">图片加载失败</div> <img v-else :src="src" :alt="alt" @load="isLoading = false" @error="handleError" style="width:100%;" /> </div> </template> <script setup> import { ref } from 'vue'; const props = defineProps(['src', 'alt']); const isLoading = ref(true); const hasError = ref(false); const handleError = () => { isLoading.value = false; hasError.value = true; }; </script> <style scoped> .image-container { width: 100%; height: 200px; } .loader { width: 100%; height: 100%; background: #f5f5f5; display: flex; align-items: center; justify-content: center; } .spinner { width: 30px; height: 30px; border: 3px solid #ccc; border-top-color: #2196f3; border-radius: 50%; animation: spin 1s linear infinite; } @keyframes spin { to { transform: rotate(360deg); } } .error { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; background: #ffebee; color: #c62828; } </style>
额外优化建议
- 固定容器宽高:提前给图片容器设置与目标图片一致的宽高,避免加载完成后页面布局跳动
- 低质量占位图(LQIP):先加载一张极小的模糊缩略图作为占位,比纯动画更贴合最终视觉效果
- 懒加载:非首屏图片使用懒加载,延迟加载时机,减少首屏空白时间
- 批量加载优化:多张图片可使用并行加载+分批渲染,避免一次性请求过多资源导致卡顿
内容的提问来源于stack exchange,提问作者Baimam Boukar Jean Jacques
相关产品推荐
相关产品推荐

