鼠标悬停时循环切换AJAX加载图片,鼠标移出时停止循环
实现模型网格图片悬停轮播效果
嘿,这个需求我太熟了!刚好之前做过类似的产品展示网格,核心就是绑定鼠标事件+定时器控制图片切换+AJAX缓存这几个点,我给你拆解成可直接用的代码和思路:
先理清楚你的HTML结构(补全并规范后)
<div class="c-grid c-grid--models"> <a href="#link-to-model" class="c-model" data-id="1"> <figure class="c-model__wrap"> <img src="http://placeholder.image" data-original="http://lazyloaded.image" class="c-model__img" alt="Model 1" > <figcaption class="c-model__name">Model Name 1</figcaption> </figure> </a> <!-- 更多模型卡片重复上面的结构,data-id对应不同的模型ID --> <a href="#link-to-model-2" class="c-model" data-id="2"> <figure class="c-model__wrap"> <img src="http://placeholder.image" data-original="http://lazyloaded.image" class="c-model__img" alt="Model 2" > <figcaption class="c-model__name">Model Name 2</figcaption> </figure> </a> </div>
核心实现思路
- 给每个
.c-model卡片绑定mouseenter和mouseleave事件 - 进入卡片时:
- 先获取当前卡片的
data-id,用它请求对应模型的图片列表(缓存请求结果,避免重复AJAX) - 记录原图地址(存在
data-original里的) - 启动定时器,每隔1秒切换图片的
src
- 先获取当前卡片的
- 离开卡片时:
- 立即清除定时器,停止轮播
- 把图片
src恢复成原图地址
具体代码实现(jQuery版本,易上手)
// 缓存AJAX请求的结果,避免重复请求 const modelImageCache = {}; $(document).on('mouseenter', '.c-model', function() { const $card = $(this); const modelId = $card.data('id'); const $img = $card.find('.c-model__img'); const originalSrc = $img.data('original'); // 如果已经缓存过该模型的图片列表,直接用 if (modelImageCache[modelId]) { startImageCycle($img, modelImageCache[modelId], originalSrc); return; } // 没有缓存的话,AJAX请求图片列表 $.ajax({ url: `/api/models/${modelId}/images`, // 替换成你的实际接口地址 method: 'GET', success: function(images) { // 缓存结果 modelImageCache[modelId] = images; // 启动轮播 startImageCycle($img, images, originalSrc); }, error: function() { console.error(`Failed to load images for model ${modelId}`); } }); }); $(document).on('mouseleave', '.c-model', function() { const $img = $(this).find('.c-model__img'); const originalSrc = $img.data('original'); // 清除定时器 clearInterval($img.data('cycleTimer')); // 恢复原图 $img.attr('src', originalSrc); }); // 封装轮播逻辑的函数 function startImageCycle($img, images, originalSrc) { // 如果图片列表为空,直接返回 if (!images || images.length === 0) return; let currentIndex = 0; // 先切换到第一张轮播图(跳过原图) $img.attr('src', images[currentIndex]); // 启动定时器,每隔1秒切换 const timer = setInterval(() => { currentIndex = (currentIndex + 1) % images.length; $img.attr('src', images[currentIndex]); }, 1000); // 把定时器存在图片元素的data里,方便离开时清除 $img.data('cycleTimer', timer); }
关键细节优化(必看)
- 缓存AJAX结果:用
modelImageCache对象存每个模型的图片列表,用户再次悬停同个模型时不用重复请求,提升性能 - 独立定时器:把定时器存在每个图片元素的
data里,避免多个卡片的定时器互相干扰 - 异常处理:AJAX请求失败时打印错误,方便调试
- 边界情况:如果图片列表为空,直接不启动轮播,避免报错
- 可选优化:图片预加载:可以在AJAX成功后,提前加载所有轮播图片,避免切换时出现空白:
// 在AJAX success里添加预加载 images.forEach(imgUrl => { const preloadImg = new Image(); preloadImg.src = imgUrl; });
原生JS版本(如果不用jQuery)
如果你项目里没引入jQuery,也可以用原生JS实现,核心逻辑一样,只是事件绑定和DOM操作换成原生API:
const modelImageCache = {}; document.addEventListener('mouseenter', function(e) { if (!e.target.closest('.c-model')) return; const card = e.target.closest('.c-model'); const modelId = card.dataset.id; const img = card.querySelector('.c-model__img'); const originalSrc = img.dataset.original; if (modelImageCache[modelId]) { startImageCycle(img, modelImageCache[modelId], originalSrc); return; } fetch(`/api/models/${modelId}/images`) .then(res => res.json()) .then(images => { modelImageCache[modelId] = images; startImageCycle(img, images, originalSrc); }) .catch(err => console.error(`Failed to load images: ${err}`)); }); document.addEventListener('mouseleave', function(e) { if (!e.target.closest('.c-model')) return; const card = e.target.closest('.c-model'); const img = card.querySelector('.c-model__img'); const originalSrc = img.dataset.original; clearInterval(img.dataset.cycleTimer); img.src = originalSrc; }); function startImageCycle(img, images, originalSrc) { if (!images || images.length === 0) return; let currentIndex = 0; img.src = images[currentIndex]; const timer = setInterval(() => { currentIndex = (currentIndex + 1) % images.length; img.src = images[currentIndex]; }, 1000); img.dataset.cycleTimer = timer; }
内容的提问来源于stack exchange,提问作者chocolata
相关产品推荐
相关产品推荐

