You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中如何为网络图片添加加载占位符或动画?

解决图片加载时显示占位内容的方案

核心逻辑

不管使用哪种技术栈,核心思路都是:

  1. 初始状态下显示占位加载器/动画
  2. 监听图片的加载完成(或失败)事件,完成后替换占位内容

原生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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 08:27:37