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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.12 16:48:02