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

基于滚动位置统计图片并更新主图计数器的技术需求

这需求我之前做过类似的,给你一套完整的实现方案,思路清晰还好用!

核心实现思路

要实现根据滚动位置判断当前主要可视的图片,核心是计算每张图片在视口内的可见区域,选出可见区域最大的那张作为当前活跃图片,然后同步更新计数器。

这里用到getBoundingClientRect()API来获取元素相对于视口的位置信息,通过这个信息可以算出元素在视口中的可见高度,以此作为判断“主要可视”的依据。

具体代码实现

1. HTML结构

先搭建基础的页面结构,包含计数器展示区和图片列表:

<!-- 固定定位的计数器 -->
<div class="counter">
  当前第 <span id="current-count">1</span> 张,共 <span id="total-count">0</span> 张
</div>

<!-- 图片容器 -->
<div class="image-container">
  <img src="https://picsum.photos/1200/800?random=1" class="scroll-image" alt="示例图片1">
  <img src="https://picsum.photos/1200/800?random=2" class="scroll-image" alt="示例图片2">
  <img src="https://picsum.photos/1200/800?random=3" class="scroll-image" alt="示例图片3">
  <img src="https://picsum.photos/1200/800?random=4" class="scroll-image" alt="示例图片4">
  <img src="https://picsum.photos/1200/800?random=5" class="scroll-image" alt="示例图片5">
</div>

2. CSS样式

让每张图片占满视口高度,计数器固定在页面左上角,保证滚动时一直可见:

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.counter {
  position: fixed;
  top: 20px;
  left: 20px;
  background-color: rgba(0, 0, 0, 0.8);
  color: #fff;
  padding: 10px 18px;
  border-radius: 6px;
  font-size: 18px;
  z-index: 999;
}

.image-container {
  display: flex;
  flex-direction: column;
}

.scroll-image {
  width: 100vw;
  height: 100vh;
  object-fit: cover; /* 保证图片比例不变,铺满容器 */
}

3. JavaScript逻辑

第一步:编写计算元素可见高度的工具函数

// 计算元素在视口中的可见高度
function getVisibleHeight(element) {
  const rect = element.getBoundingClientRect();
  const viewportHeight = window.innerHeight || document.documentElement.clientHeight;

  // 元素完全在视口外,返回0
  if (rect.bottom < 0 || rect.top > viewportHeight) {
    return 0;
  }

  // 计算实际可见的高度
  const visibleTop = Math.max(rect.top, 0);
  const visibleBottom = Math.min(rect.bottom, viewportHeight);
  return visibleBottom - visibleTop;
}

第二步:编写更新计数器的核心函数

遍历所有图片,找到可见高度最大的那张,更新计数器显示:

function updateCounter() {
  const images = document.querySelectorAll('.scroll-image');
  let maxVisibleHeight = 0;
  let currentActiveIndex = 0;

  images.forEach((img, index) => {
    const visibleHeight = getVisibleHeight(img);
    // 找到可见高度最大的图片
    if (visibleHeight > maxVisibleHeight) {
      maxVisibleHeight = visibleHeight;
      currentActiveIndex = index;
    }
  });

  // 更新DOM,注意索引从0开始,所以要+1
  document.getElementById('current-count').textContent = currentActiveIndex + 1;
}

第三步:初始化与滚动监听(加防抖优化性能)

滚动事件会频繁触发,用防抖函数减少计算次数,提升性能:

// 防抖函数:延迟执行,避免频繁触发
function debounce(func, delay = 100) {
  let timeoutId;
  return function() {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => func.apply(this, arguments), delay);
  };
}

// 初始化计数器的总数量
document.getElementById('total-count').textContent = document.querySelectorAll('.scroll-image').length;

// 页面加载完成后先执行一次,确保初始状态正确
updateCounter();

// 监听滚动事件,用防抖包裹核心函数
window.addEventListener('scroll', debounce(updateCounter));
优化与注意事项
  • 防抖延迟调整:防抖的delay参数可以根据需求修改,数值越小响应越及时,但性能消耗略高;反之则更流畅,建议在50-150ms之间调整。
  • 动态加载图片:如果图片是异步加载的,要在图片的load事件触发后再调用updateCounter(),避免初始计算时图片还未渲染导致的错误。
  • 自定义判断逻辑:如果你觉得“可见高度最大”不符合需求,也可以改成判断图片中心是否在视口内,只需要修改updateCounter里的判断逻辑即可,比如:
    // 判断元素中心是否在视口内
    function isCenterInViewport(element) {
      const rect = element.getBoundingClientRect();
      const viewportHeight = window.innerHeight;
      const elementCenterY = rect.top + rect.height / 2;
      return elementCenterY >= 0 && elementCenterY <= viewportHeight;
    }
    
    然后在遍历图片时,找到第一个满足这个条件的图片即可。

内容的提问来源于stack exchange,提问作者JSamarjiev

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 07:55:24