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

Flutter中复制Widget方法:实现图片单次加载并添加同形阴影

解决方案

下面提供几种可行的方案,都能实现只加载一次图片就能生成原图和对应阴影的效果:

1. 原生JS + Canvas 方案

核心思路是先加载一次图片,再把这张已加载的图片分别绘制到两个Canvas(一个显示原图,一个做阴影处理),完全复用同一份图片资源,不会发起二次请求。

代码示例:

// 创建图片对象,仅发起一次加载请求
const targetImg = new Image();
targetImg.src = '你的图片地址';
// 跨域图片需开启CORS
targetImg.crossOrigin = 'anonymous';

targetImg.onload = function() {
  // 处理原图Canvas
  const originalCanvas = document.createElement('canvas');
  const originalCtx = originalCanvas.getContext('2d');
  originalCanvas.width = targetImg.width;
  originalCanvas.height = targetImg.height;
  originalCtx.drawImage(targetImg, 0, 0);
  document.body.appendChild(originalCanvas);

  // 处理阴影Canvas
  const shadowCanvas = document.createElement('canvas');
  const shadowCtx = shadowCanvas.getContext('2d');
  shadowCanvas.width = targetImg.width;
  shadowCanvas.height = targetImg.height;

  // 给阴影层加滤镜和位移
  shadowCtx.filter = 'brightness(0.3) blur(5px)';
  shadowCtx.drawImage(targetImg, 0, 0);
  shadowCanvas.style.cssText = `
    position: absolute;
    transform: translate(8px, 8px);
    z-index: -1;
  `;
  
  document.body.appendChild(shadowCanvas);
};

2. 浏览器缓存 + CSS 伪元素方案

利用浏览器的图片缓存机制,让伪元素复用img标签已加载的图片,只需要一个img标签就能实现效果。

代码示例:

.image-wrap {
  position: relative;
  display: inline-block;
}

.image-wrap img {
  display: block;
  position: relative;
  z-index: 1;
}

/* 伪元素作为阴影层,复用缓存的图片 */
.image-wrap:after {
  content: '';
  position: absolute;
  top: 10px;
  left: 10px;
  width: 100%;
  height: 100%;
  background-image: url('你的图片地址');
  background-size: cover;
  /* 自定义阴影滤镜 */
  filter: grayscale(100%) brightness(0.4) blur(4px);
  z-index: 0;
}
<div class="image-wrap">
  <img src="你的图片地址" alt="目标图片">
</div>

注:如果是跨域图片,需要服务器配置CORS允许缓存,否则浏览器可能会重新发起请求。

3. React 框架下的实现方案

在React中可以通过useRef缓存已加载的图片对象,后续原图和阴影层都复用这个对象:

import { useRef, useEffect, useState } from 'react';

function ImageWithCustomShadow() {
  const cachedImg = useRef(null);
  const [isLoaded, setIsLoaded] = useState(false);

  useEffect(() => {
    // 仅加载一次图片
    const img = new Image();
    img.src = '你的图片地址';
    img.crossOrigin = 'anonymous';
    img.onload = () => {
      cachedImg.current = img;
      setIsLoaded(true);
    };
  }, []);

  if (!isLoaded) return <div>加载中...</div>;

  return (
    <div style={{ position: 'relative', display: 'inline-block' }}>
      {/* 原图 */}
      <img 
        src={cachedImg.current.src} 
        alt="原图" 
        style={{ position: 'relative', zIndex: 1 }} 
      />
      {/* 阴影Canvas */}
      <canvas
        width={cachedImg.current.width}
        height={cachedImg.current.height}
        style={{
          position: 'absolute',
          top: '8px',
          left: '8px',
          zIndex: 0,
          filter: 'blur(6px) brightness(0.2)'
        }}
        ref={(canvas) => {
          if (canvas) {
            const ctx = canvas.getContext('2d');
            ctx.drawImage(cachedImg.current, 0, 0);
          }
        }}
      />
    </div>
  );
}

export default ImageWithCustomShadow;

内容的提问来源于stack exchange,提问作者Felipe

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 18:34:54