如何为Next.js Image组件src切换添加淡入淡出动画效果
Next.js Image组件悬停切换淡入淡出实现方案
直接切换单个Image组件的src无法实现平滑过渡——src更新后旧图片会被立即替换,不存在两个状态交叉的动画区间,最稳定且代码量最小的实现方案是叠放两张预加载的图片,通过透明度变化实现淡入淡出效果。
方案1:Tailwind 实现(无需额外CSS,推荐)
核心逻辑是用相对定位容器包裹两张同尺寸的Image,通过悬停状态控制两张图的透明度,搭配CSS过渡实现动画:
import Image from 'next/image'; import { useState } from 'react'; export default function Logo() { const [isHovered, setIsHovered] = useState(false); return ( <div className="relative w-fit" onMouseEnter={() => setIsHovered(true)} onMouseLeave={() => setIsHovered(false)} > {/* 默认态logo */} <Image src="/logo.png" width={237} height={64} priority className={`absolute top-0 left-0 transition-opacity duration-300 ease-in-out ${ isHovered ? 'opacity-0' : 'opacity-100' }`} /> {/* 悬停态logo */} <Image src="/hover-logo.png" width={237} height={64} priority className={`transition-opacity duration-300 ease-in-out ${ isHovered ? 'opacity-100' : 'opacity-0' }`} /> </div> ) }
- 调整
duration-300的数值可以修改动画速度:duration-150更快更利落,duration-500更舒缓 - 两张图都加了
priority属性,页面加载时就会预加载,悬停时不会出现新图加载导致的空白、闪烁问题 - 鼠标事件绑定在外层容器上,不会因为图片透明度变化触发事件误判
方案2:原生CSS实现(无需JS状态,更简洁)
如果不想写React状态,直接用CSS的:hover伪类就能实现,代码更精简:
首先加样式:
.logo-wrap { position: relative; width: fit-content; } .logo-default, .logo-hover { transition: opacity 0.3s ease-in-out; } .logo-default { position: absolute; inset: 0; opacity: 1; } .logo-hover { opacity: 0; } .logo-wrap:hover .logo-default { opacity: 0; } .logo-wrap:hover .logo-hover { opacity: 1; }
对应组件代码:
import Image from 'next/image'; export default function Logo() { return ( <div className="logo-wrap"> <Image src="/logo.png" width={237} height={64} priority className="logo-default" /> <Image src="/hover-logo.png" width={237} height={64} priority className="logo-hover" /> </div> ) }
注意事项
不推荐硬用单Image切换src做动画:如果要在单个组件上实现效果,需要监听新图的onLoad事件,在新图加载完成后再切换透明度类名,逻辑冗余,还容易在快速反复悬停时出现状态错乱、图片闪跳的问题,叠两层的方案没有这类边界问题,兼容所有Next.js版本。
内容的提问来源于stack exchange,提问作者Ali Altun
相关产品推荐
相关产品推荐

