react实现楼层效果
实现楼层效果的基本思路
楼层效果通常指页面滚动时,不同区块(楼层)依次固定在视口中的交互效果。React中可通过监听滚动事件、计算元素位置并结合CSS实现。
核心步骤
监听滚动事件
使用useEffect监听window的滚动事件,注意在组件卸载时移除监听以避免内存泄漏。
useEffect(() => {
const handleScroll = () => {
// 计算当前滚动位置对应的楼层
};
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
计算元素位置
通过getBoundingClientRect()获取每个楼层元素相对于视口的位置,结合window.scrollY判断当前应固定的楼层。
const floorElements = document.querySelectorAll('.floor');
floorElements.forEach((el) => {
const rect = el.getBoundingClientRect();
if (rect.top <= 0 && rect.bottom >= 0) {
// 当前可视区域匹配该楼层
}
});
动态切换CSS类
为当前活跃楼层添加固定定位类(如.active-floor),其他楼层恢复默认样式。
.floor {
height: 100vh;
transition: transform 0.3s;
}
.active-floor {
position: sticky;
top: 0;
}
完整组件示例
import React, { useState, useEffect } from 'react';
const FloorNavigation = () => {
const [activeFloor, setActiveFloor] = useState(0);
useEffect(() => {
const floors = document.querySelectorAll('.floor');
const handleScroll = () => {
floors.forEach((floor, index) => {
const rect = floor.getBoundingClientRect();
if (rect.top <= 100 && rect.bottom >= 100) {
setActiveFloor(index);
}
});
};
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
return (
<div>
{[1, 2, 3, 4].map((floor, index) => (
<div
key={index}
className={`floor ${index === activeFloor ? 'active-floor' : ''}`}
style={{ background: `hsl(${index * 90}, 50%, 80%)` }}
>
<h2>Floor {floor}</h2>
</div>
))}
</div>
);
};
优化方案
节流滚动事件
高频滚动事件可能导致性能问题,建议使用lodash.throttle或自定义节流函数。
import throttle from 'lodash.throttle';
const throttledScroll = throttle(handleScroll, 200);
window.addEventListener('scroll', throttledScroll);
Intersection Observer API 现代浏览器支持的更高效元素观察方案,替代手动计算位置。
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
setActiveFloor(entry.target.dataset.floor);
}
});
}, { threshold: 0.5 });
useEffect(() => {
const floors = document.querySelectorAll('.floor');
floors.forEach(floor => observer.observe(floor));
return () => observer.disconnect();
}, []);
导航指示器 添加侧边导航栏实时指示当前楼层位置,增强用户体验。
<div className="floor-indicator">
{[1, 2, 3, 4].map((_, index) => (
<button
key={index}
className={index === activeFloor ? 'active' : ''}
onClick={() => {
document.querySelectorAll('.floor')[index].scrollIntoView();
}}
/>
))}
</div>






