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

如何实现鼠标移动时图片平滑跟随并动态显隐的效果?

解决鼠标跟随图片平滑显隐的问题

我看了你的代码,想要实现类似目标网站的鼠标移动时图片跟随并动态显隐的效果,咱们一步步来修正代码里的问题:

主要问题分析

  • 元素位置计算复杂易出错:原来的getPosition函数用循环offsetParent的方式计算位置,不仅繁琐,还容易因为滚动或嵌套元素出现偏差,现代浏览器用getBoundingClientRect()更高效准确。
  • 所有图片同时移动导致重叠:每次鼠标移动时你遍历所有图片并设置相同位置,这样所有图片叠在一起,视觉上只有一张,而且大量DOM操作会影响性能。
  • 过渡效果冲突:CSS和JS里重复设置transition属性,导致动画效果混乱,应该统一管理过渡规则。
  • 定时器堆积:每次mousemove都给每个图片添加定时器,会造成大量定时器同时运行,拖慢页面性能。
  • HTML类名笔误:<div class="giv__photo__block">里的giv应该是gif,虽然不影响选择器,但规范命名能避免后续不必要的bug。

修正后的完整代码

HTML(修正类名笔误)

<div class="gif__portfolio__inner"> 
    <div class="gif__photo__block"> 
        <img src="img/gif/photo-2.png" alt="" class="gif__photo gif__photo__one"> 
        <img src="img/gif/photo-2.png" alt="" class="gif__photo gif__photo__two"> 
        <img src="img/gif/photo-3.png" alt="" class="gif__photo gif__photo__three"> 
        <img src="img/gif/photo-4.png" alt="" class="gif__photo gif__photo__four"> 
        <img src="img/gif/photo-5.png" alt="" class="gif__photo gif__photo__five"> 
        <img src="img/gif/photo-6.png" alt="" class="gif__photo gif__photo__six"> 
        <img src="img/gif/photo-7.png" alt="" class="gif__photo gif__photo__seven"> 
        <img src="img/gif/photo-8.png" alt="" class="gif__photo gif__photo__eight"> 
    </div> 
</div>

CSS(统一过渡效果,简化规则)

.gif__portfolio__inner { 
    overflow: hidden; 
    position: relative;
    /* 给父容器设置宽高,确保鼠标能触发事件 */
    width: 100vw;
    height: 500px;
    background-color: #f0f0f0;
} 
.gif__photo__block {
    position: relative;
    width: 100%;
    height: 100%;
}
.gif__photo { 
    position: absolute; 
    z-index: 10; 
    opacity: 0; 
    border-radius: 50%;
    /* 统一过渡:位置平滑移动,透明度和圆角渐变 */
    transition: left 0.2s ease-out, top 0.2s ease-out, opacity 0.5s ease-out, border-radius 0.5s ease-out;
    /* 初始位置设为父容器外,避免初始闪烁 */
    left: -100px;
    top: -100px;
    width: 80px;
    height: 80px;
    object-fit: cover;
} 
.gif__photo.active { 
    opacity: 1;
    border-radius: 0;
}

JavaScript(优化逻辑,避免性能问题)

function initPhotoFollow() { 
    const gifPortfolio = document.querySelector('.gif__portfolio__inner'); 
    const pictures = document.querySelectorAll(".gif__photo");
    let currentIndex = 0; // 循环使用图片,避免重复创建元素
    let isAnimating = false; // 防止短时间内重复触发动画

    // 获取元素相对于视口的位置,替代原来的getPosition
    function getElementRect(element) {
        return element.getBoundingClientRect();
    }

    function handleMouseMove(e) { 
        if (isAnimating) return; // 如果有动画在运行,跳过当前触发
        const parentRect = getElementRect(gifPortfolio); 
        // 计算鼠标在父容器内的坐标
        const mouseX = e.clientX - parentRect.left;
        const mouseY = e.clientY - parentRect.top;
        // 取出当前要显示的图片
        const currentPic = pictures[currentIndex];
        // 计算图片位置(让图片中心对准鼠标)
        const xPosition = mouseX - currentPic.offsetWidth / 2;
        const yPosition = mouseY - currentPic.offsetHeight / 2;

        // 设置图片位置
        currentPic.style.left = `${xPosition}px`;
        currentPic.style.top = `${yPosition}px`;
        // 激活图片(显示+变圆角)
        currentPic.classList.add('active');

        isAnimating = true;
        // 动画结束后重置状态,切换到下一张图片
        setTimeout(() => {
            currentPic.classList.remove('active');
            // 延迟等待透明度过渡完成后再重置位置,避免闪烁
            setTimeout(() => {
                currentPic.style.left = '-100px';
                currentPic.style.top = '-100px';
                isAnimating = false;
                // 切换到下一张图片,循环使用
                currentIndex = (currentIndex + 1) % pictures.length;
            }, 500);
        }, 400);
    } 

    gifPortfolio.addEventListener("mousemove", handleMouseMove, false); 
} 

// 确保DOM加载完成后执行
document.addEventListener('DOMContentLoaded', initPhotoFollow);

关键优化点说明

  • 使用getBoundingClientRect()计算位置:这个方法直接返回元素相对于视口的矩形位置,计算鼠标在父容器内的坐标更简单准确,避免了原来循环offsetParent的复杂逻辑。
  • 循环使用图片:通过currentIndex循环切换要显示的图片,避免所有图片同时移动,同时减少DOM操作次数,提升性能。
  • 添加动画节流:用isAnimating变量防止短时间内重复触发动画,避免定时器堆积和视觉混乱。
  • 统一过渡规则:在CSS里一次性定义所有需要过渡的属性,JS只负责添加/移除类来触发动画,避免过渡属性冲突。
  • 明确父容器尺寸:给.gif__portfolio__inner设置宽高,确保鼠标能在容器内触发mousemove事件,否则容器高度为0的话事件不会触发。

这样修改后,就能实现鼠标移动时,图片依次跟随鼠标位置出现,从圆形变为方形,然后淡出,再切换下一张图片的平滑效果啦~

内容的提问来源于stack exchange,提问作者Павел

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 03:07:48