React:实现固定头部感知下方Div并触发调整逻辑
根据滚动位置切换头部Logo颜色方案
核心思路
通过监听页面滚动事件,定位头部下方对应的页面区块,计算该区块背景色的明暗度,据此切换Logo的颜色样式,实现适配不同背景的视觉效果。
实现步骤与代码示例
1. 基础结构与样式
先搭建页面结构,固定头部包含Logo,页面划分不同明暗的区块:
<!-- 固定头部 --> <header class="header"> <div class="logo" id="siteLogo">Logo</div> </header> <!-- 页面区块 --> <section class="block block-dark">深色区块</section> <section class="block block-light">浅色区块</section> <section class="block block-dark">深色区块</section> <section class="block block-light">浅色区块</section>
对应的CSS样式:
.header { position: fixed; top: 0; width: 100%; padding: 1rem; background: transparent; } .logo { font-size: 1.5rem; font-weight: bold; transition: color 0.3s ease; } /* Logo颜色状态类 */ .logo-dark { color: #000; } .logo-light { color: #fff; } .block { height: 100vh; display: flex; align-items: center; justify-content: center; font-size: 2rem; } .block-dark { background-color: #222; color: #fff; } .block-light { background-color: #eee; color: #000; }
2. 滚动监听与逻辑处理
编写JavaScript实现核心功能,包含滚动防抖、区块定位、亮度计算:
const header = document.querySelector('.header'); const logo = document.getElementById('siteLogo'); const blocks = document.querySelectorAll('.block'); const headerHeight = header.offsetHeight; // 防抖函数,避免滚动事件频繁触发 function debounce(func, delay = 100) { let timeoutId; return (...args) => { clearTimeout(timeoutId); timeoutId = setTimeout(() => func.apply(this, args), delay); }; } // 计算颜色亮度(0-255,127为分界点) function getColorBrightness(hexColor) { // 处理简写hex(如#fff) const hex = hexColor.replace('#', ''); const r = parseInt(hex.length === 3 ? hex[0].repeat(2) : hex.slice(0, 2), 16); const g = parseInt(hex.length === 3 ? hex[1].repeat(2) : hex.slice(2, 4), 16); const b = parseInt(hex.length === 3 ? hex[2].repeat(2) : hex.slice(4, 6), 16); // 加权亮度公式,符合人眼感知 return (r * 299 + g * 587 + b * 114) / 1000; } // 判断当前头部下方对应的区块 function getCurrentUnderlyingBlock() { const scrollTop = window.scrollY; // 取头部中间位置作为检测点,避免边缘切换时的频繁跳动 const targetY = scrollTop + headerHeight / 2; for (const block of blocks) { const blockTop = block.offsetTop; const blockBottom = blockTop + block.offsetHeight; if (targetY >= blockTop && targetY < blockBottom) { return block; } } return null; } // 更新Logo颜色 function updateLogoColor() { const currentBlock = getCurrentUnderlyingBlock(); if (!currentBlock) return; const bgColor = window.getComputedStyle(currentBlock).backgroundColor; // 将RGB格式转换为HEX let hexColor; if (bgColor.startsWith('rgb')) { const rgb = bgColor.match(/\d+/g).map(Number); hexColor = `#${((1 << 24) + (rgb[0] << 16) + (rgb[1] << 8) + rgb[2]).toString(16).slice(1)}`; } else { hexColor = bgColor; } const brightness = getColorBrightness(hexColor); // 根据亮度切换Logo类 if (brightness > 127) { logo.classList.add('logo-dark'); logo.classList.remove('logo-light'); } else { logo.classList.add('logo-light'); logo.classList.remove('logo-dark'); } } // 初始加载时执行一次,确保初始状态正确 updateLogoColor(); // 绑定防抖后的滚动事件 window.addEventListener('scroll', debounce(updateLogoColor));
关键细节说明
- 防抖处理:滚动事件会频繁触发,用防抖函数减少计算次数,提升页面性能
- 检测点选择:取头部中间位置作为检测点,避免头部边缘区块切换时的Logo颜色频繁跳动
- 亮度计算:使用加权公式计算颜色亮度,结果更符合人眼对明暗的实际感知
- 初始状态处理:页面加载完成后立即执行一次颜色更新,避免初始状态Logo颜色与背景不匹配
内容的提问来源于stack exchange,提问作者Bert1986
相关产品推荐
相关产品推荐

