使用HTML/CSS/JS实现滚动时切换选中按钮及关联图片方案咨询
实现方案
这个交互完全可以使用Intersection Observer实现,相比传统的scroll事件监听,它性能更高,不需要频繁计算滚动位置,也不会出现防抖节流带来的延迟问题。
所需技术点
- CSS:
position: sticky固定左侧按钮栏和右侧图片展示区,自定义激活态样式区分选中按钮,控制图片的显示隐藏 - JS:Intersection Observer API 监听对应锚点区块的视口进入状态,触发激活态和图片切换
完整实现代码
我基于你现有的代码结构做了适配调整,直接可以运行:
<!DOCTYPE html> <html lang="zh-CN"> <head> <style> /* 全局布局 */ .container { display: flex; gap: 50px; padding: 20px; } /* 左侧按钮栏 */ .btn-group { display: flex; flex-direction: column; gap: 10px; position: sticky; top: 20px; align-self: flex-start; } .btn-group button { width: 100px; height: 100px; border: none; cursor: pointer; transition: all 0.3s; } /* 按钮激活态样式 */ .btn-group button.active { background-color: red; color: #fff; } /* 右侧内容区 */ .content-area { flex: 1; } /* 右侧图片展示区(固定) */ .img-display { position: sticky; top: 20px; align-self: flex-start; height: 300px; margin-bottom: 20px; } .img-display img { width: 100%; height: 100%; object-fit: cover; display: none; } /* 图片激活显示 */ .img-display img.active { display: block; } /* 滚动触发锚点区块 */ .scroll-section { height: 400px; margin-bottom: 30px; background-color: #f5f5f5; display: flex; align-items: center; justify-content: center; font-size: 24px; } </style> </head> <body> <div class="container"> <!-- 左侧按钮组 --> <section class="btn-group"> <button class="active" data-index="0">Button 1</button> <button data-index="1">Button 2</button> <button data-index="2">Button 3</button> </section> <!-- 右侧内容区 --> <div class="content-area"> <!-- 固定展示的图片区 --> <div class="img-display"> <img src="https://picsum.photos/800/300?random=1" alt="图1" class="active" data-index="0"> <img src="https://picsum.photos/800/300?random=2" alt="图2" data-index="1"> <img src="https://picsum.photos/800/300?random=3" alt="图3" data-index="2"> </div> <!-- 滚动触发的锚点区块 --> <div class="scroll-section" data-index="0">区块1</div> <div class="scroll-section" data-index="1">区块2</div> <div class="scroll-section" data-index="2">区块3</div> </div> </div> <script> // 获取所有元素 const buttons = document.querySelectorAll('.btn-group button') const imgs = document.querySelectorAll('.img-display img') const sections = document.querySelectorAll('.scroll-section') // 切换激活态的公共方法 function switchActive(index) { // 切换按钮激活态 buttons.forEach(btn => btn.classList.remove('active')) buttons[index].classList.add('active') // 切换图片显示 imgs.forEach(img => img.classList.remove('active')) imgs[index].classList.add('active') } // 初始化Intersection Observer const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { // 拿到进入视口的区块对应的索引 const curIndex = Number(entry.target.dataset.index) switchActive(curIndex) } }) }, { // 触发阈值:区块30%进入视口时触发 threshold: 0.3 }) // 监听所有锚点区块 sections.forEach(section => observer.observe(section)) // 可选:点击按钮也可以切换 buttons.forEach(btn => { btn.addEventListener('click', () => { const index = Number(btn.dataset.index) // 滚动到对应区块 sections[index].scrollIntoView({behavior: 'smooth'}) }) }) </script> </body> </html>
可选替代方案
如果要兼容特别老的浏览器(不支持Intersection Observer),也可以用scroll事件实现,需要监听window的scroll事件,实时计算滚动高度和各个区块的offsetTop对比判断当前应该激活的索引,但是要注意加防抖处理避免性能问题。
内容的提问来源于stack exchange,提问作者Avedis Maroukian
相关产品推荐
相关产品推荐

