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

如何实现滚动时基于视口底部20%区域切换body背景色?

解决方案:基于滚动事件的精准背景色切换

直接监听滚动事件并计算目标位置的方式,比IntersectionObserver更易控制逻辑,能精准匹配视口底部20%的区域对应的区块。以下是具体实现:

核心思路

  1. 计算视口底部20%位置的绝对坐标:滚动距离 + 视口高度 × 0.8
  2. 遍历所有区块,找到该坐标落在的目标区块
  3. 提取目标区块的data-background值,设置为body的背景色
  4. 优化性能:用useRef缓存区块DOM引用,避免重复查询;用状态避免重复设置背景色

React 代码实现

import { useEffect, useRef, useState } from 'react';

const ScrollBgSwitcher = () => {
  // 缓存所有区块的DOM引用
  const blockRefs = useRef([]);
  // 记录当前激活的背景色,避免重复DOM操作
  const [activeBg, setActiveBg] = useState('');

  useEffect(() => {
    const updateBodyBg = () => {
      // 计算视口底部20%的绝对位置
      const targetY = window.scrollY + window.innerHeight * 0.8;

      // 从下往上遍历区块,优先匹配最下方的目标区块
      for (let i = blockRefs.current.length - 1; i >= 0; i--) {
        const block = blockRefs.current[i];
        if (!block) continue;

        const rect = block.getBoundingClientRect();
        const blockTop = rect.top + window.scrollY;
        const blockBottom = rect.bottom + window.scrollY;

        // 检查目标点是否落在当前区块内
        if (targetY >= blockTop && targetY <= blockBottom) {
          const newBg = block.dataset.background;
          if (newBg !== activeBg) {
            document.body.style.backgroundColor = newBg;
            setActiveBg(newBg);
          }
          break;
        }
      }
    };

    // 页面加载时初始化背景色
    updateBodyBg();
    // 绑定滚动事件,passive优化性能
    window.addEventListener('scroll', updateBodyBg, { passive: true });

    // 组件卸载时清理事件监听
    return () => {
      window.removeEventListener('scroll', updateBodyBg);
    };
  }, [activeBg]);

  // 生成10个带不同背景色的区块
  const colorList = [
    '#ff4444', '#00C851', '#33b5e5', '#ffbb33', '#aa66cc',
    '#ff8800', '#0099cc', '#99cc00', '#ff4444', '#33b5e5'
  ];

  const blocks = colorList.map((color, idx) => (
    <section
      key={idx}
      ref={el => el && (blockRefs.current[idx] = el)}
      data-background={color}
      style={{
        height: '100vh',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        color: '#fff',
        fontSize: '2.5rem',
        fontWeight: 'bold'
      }}
    >
      区块 {idx + 1}
    </section>
  ));

  return <div>{blocks}</div>;
};

export default ScrollBgSwitcher;

关键细节说明

  • 从下往上遍历:当滚动时,可能多个区块与目标位置有重叠,从下往上找第一个匹配的区块,能确保是当前视口底部20%对应的正确区块
  • passive事件监听:{ passive: true }告诉浏览器滚动事件不会调用preventDefault(),提升滚动流畅度
  • 缓存DOM引用:useRef保存区块DOM,避免每次滚动都通过querySelector查询,减少性能开销
  • 避免重复更新:用activeBg状态记录当前背景色,只有当颜色变化时才更新body样式,减少不必要的DOM操作

关于IntersectionObserver的补充说明

如果坚持用IntersectionObserver,需要调整根边距来匹配视口底部20%区域,配置如下:

const observerConfig = {
  root: null,
  // 把视口上80%区域排除,只监听底部20%
  rootMargin: `0px 0px ${-window.innerHeight * 0.8}px 0px`,
  threshold: 0.1 // 区块有10%进入目标区域时触发
};

但这种方式需要处理多个区块同时交叉的优先级问题,逻辑复杂度更高,不如直接计算坐标的方式直观可控。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 12:48:24