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
相关产品推荐
相关产品推荐

