导航栏图片滚动匹配视口区域切换失效问题求助
导航栏图片滚动切换失效问题
我已经实现了导航栏图片的鼠标悬停切换效果,但当页面滚动到对应ID的区域进入视口时,无法触发相同的图片切换。悬停功能正常,滚动切换无效果。
现有代码
导航栏代码
<div class="number"><a href="#3"><img class="ai" src="https://unsplash.com/photos/Z1wosLgwGT8" onmouseover="this.src='https://unsplash.com/photos/q98u_gIRs6I'" onmouseout="this.src='https://unsplash.com/photos/Z1wosLgwGT8'" alt="3"></a></div>
页面区域代码
<div class="test" id="1"></div> <div class="test" id="2"></div> <div class="test" id="3"></div> <div class="test" id="4"></div>
已编写的JavaScript代码
const testDiv = document.querySelector("#3"); const aiImg = document.querySelector(".ai"); window.addEventListener("scroll", function() { const viewportHeight = window.innerHeight; const divTop = testDiv.getBoundingClientRect().top; const divBottom = testDiv.getBoundingClientRect().bottom; if (divTop <= viewportHeight && divBottom >= 0) { aiImg.src = "https://unsplash.com/photos/q98u_gIRs6I"; } });
问题原因及修复方案
核心问题
- 纯数字ID的兼容性隐患:虽然HTML5允许数字开头的ID,但部分环境下
querySelector("#3")可能无法正确匹配元素,容易引发选择器失效。 - 缺少离开视口的还原逻辑:当前代码只处理了进入视口的切换,未考虑元素离开视口时的图片还原,导致图片一旦切换就无法恢复初始状态。
- 滚动事件性能问题:滚动事件触发频率极高,直接在回调中执行DOM操作可能造成页面卡顿。
修复后的代码
调整HTML(优化ID命名)
<!-- 导航栏 --> <div class="number"><a href="#section-3"><img class="ai" src="https://unsplash.com/photos/Z1wosLgwGT8" onmouseover="this.src='https://unsplash.com/photos/q98u_gIRs6I'" onmouseout="this.src='https://unsplash.com/photos/Z1wosLgwGT8'" alt="3"></a></div> <!-- 页面区域 --> <div class="test" id="section-1"></div> <div class="test" id="section-2"></div> <div class="test" id="section-3"></div> <div class="test" id="section-4"></div>
优化后的JavaScript
const testDiv = document.querySelector("#section-3"); const aiImg = document.querySelector(".ai"); // 统一维护图片地址,避免重复代码 const originalSrc = "https://unsplash.com/photos/Z1wosLgwGT8"; const hoverSrc = "https://unsplash.com/photos/q98u_gIRs6I"; // 节流函数:限制滚动事件触发频率,优化性能 function throttle(func, delay = 100) { let timer = null; return function() { if (!timer) { timer = setTimeout(() => { func.apply(this, arguments); timer = null; }, delay); } }; } function handleViewportCheck() { const viewportHeight = window.innerHeight; const rect = testDiv.getBoundingClientRect(); const isInViewport = rect.top <= viewportHeight && rect.bottom >= 0; aiImg.src = isInViewport ? hoverSrc : originalSrc; } // 绑定节流后的滚动事件 window.addEventListener("scroll", throttle(handleViewportCheck)); // 页面加载时执行一次,处理初始状态 handleViewportCheck();
进阶优化方案(使用原生API)
可以用浏览器原生的IntersectionObserver替代滚动事件监听,性能更优且代码更简洁:
const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { aiImg.src = entry.isIntersecting ? hoverSrc : originalSrc; }); }, { threshold: 0.1 }); // 元素10%进入视口时触发 observer.observe(testDiv);
内容的提问来源于stack exchange,提问作者kbow
相关产品推荐
相关产品推荐

