30-seconds-of-react项目:使用useBodyScrollLock钩子实现滚动锁定
什么是滚动锁定?
滚动锁定是一种常见的前端交互技术,主要用于模态框(Modal)、侧边栏菜单等场景。当这些组件出现时,我们通常希望禁止页面背景内容的滚动,以避免用户操作混乱,提升用户体验。
useBodyScrollLock钩子解析
这个自定义钩子通过修改body元素的overflow样式属性来实现滚动锁定:
const useBodyScrollLock = () => {
React.useLayoutEffect(() => {
// 获取body元素原始的overflow值
const originalStyle = window.getComputedStyle(document.body).overflow;
// 设置body元素overflow为hidden,禁止滚动
document.body.style.overflow = 'hidden';
// 组件卸载时恢复原始样式
return () => (document.body.style.overflow = originalStyle);
}, []);
};
技术要点解析
-
useLayoutEffect:与useEffect类似,但会在DOM变更后同步触发。这里使用它确保在渲染前就锁定滚动,避免闪烁。
-
getComputedStyle:获取元素当前计算后的样式值,这里用于保存body元素的原始overflow值。
-
清理函数:返回的函数会在组件卸载时执行,恢复body元素的原始overflow值,确保不影响页面其他部分。
实际应用示例
下面是一个完整的模态框组件示例,展示了如何使用useBodyScrollLock:
const Modal = ({ onClose }) => {
useBodyScrollLock(); // 调用钩子锁定滚动
return (
<div style={{
zIndex: 100,
background: 'rgba(0,0,0,0.25)',
display: 'flex',
justifyContent: 'center',
alignItems: 'center'
}}>
<p
style={{ padding: 8, borderRadius: 8, background: '#fff' }}
onClick={onClose}
>
滚动已锁定! <br /> 点击我解锁
</p>
</div>
);
};
const MyApp = () => {
const [modalOpen, setModalOpen] = React.useState(false);
return (
<div style={{
height: '400vh',
textAlign: 'center',
paddingTop: 100,
background: 'linear-gradient(to bottom, #1fa2ff, #12d8fa, #a6ffcb)'
}}>
<button onClick={() => setModalOpen(true)}>打开模态框</button>
{modalOpen && <Modal onClose={() => setModalOpen(false)} />}
</div>
);
};
使用场景与注意事项
适用场景
- 模态对话框
- 全屏菜单
- 图片查看器
- 任何需要阻止背景滚动的交互组件
注意事项
- 性能影响:频繁切换滚动锁定可能会影响页面性能
- 嵌套使用:多个组件同时调用时需要注意样式恢复的顺序
- 移动端适配:某些移动设备可能需要额外处理touch事件
- 可访问性:确保锁定滚动时焦点管理得当,不影响键盘导航
进阶思考
对于更复杂的场景,可以考虑以下扩展:
- 添加对移动端touch事件的阻止
- 实现嵌套滚动锁定的计数机制
- 结合React Portal使用,处理不同层级的滚动锁定
这个简洁而强大的钩子展示了React自定义钩子在解决常见UI问题上的优雅之处,通过封装副作用逻辑,使组件代码更加清晰可维护。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考