我想让我的身体在使用鼠标滚轮时停止滚动,而我的网站上的Modal(来自http://twitter.github.com/bootstrap)是打开的。
当模式被打开时,我试图调用下面的javascript片段,但没有成功
$(window).scroll(function() { return false; });
AND
$(window).live('scroll', function() { return false; });
请注意,我们的网站放弃了对IE6的支持,IE7+需要兼容。
大部分的片段都在这里,但我没有看到任何答案把它们放在一起。
这个问题有三个方面。
(1)防止底层页面滚动
$('body').css('overflow', 'hidden')
(2)并移除滚动条
var handler = function (e) { e.preventDefault() }
$('.modal').bind('mousewheel touchmove', handler)
(3)模态解散时进行清理
$('.modal').unbind('mousewheel touchmove', handler)
$('body').css('overflow', '')
如果模式不是全屏,那么将.modal绑定应用到全屏覆盖。
这是TypeScript中的一种解决方案,可以轻松地阻止事件扩展,也可以处理移动设备。当禁用垂直滚动条时,这也不会导致水平跳转。
只需使用底部的导出函数,例如任何HTML元素上的onclick处理程序。如果不是在NodeJS环境中运行,只需删除该进程。客户端检查。
/**
* Handles scroll events for modal content
*/
const events = [
'DOMMouseScroll',
'mousewheel',
'wheel',
'touchmove',
'keydown',
'mousedown',
'scroll',
];
const preventDefault = (e: Event) => {
e.preventDefault();
e.stopPropagation();
return false;
};
let currentY: number;
const disableScroll = () => {
currentY = window.scrollY;
events.forEach((event) => {
window.addEventListener(event, preventDefault, {
passive: false,
});
});
const bodyStyle = document.body.style;
bodyStyle.setProperty('touch-action', 'none');
bodyStyle.setProperty('position', 'fixed');
bodyStyle.setProperty('overflow-y', 'scroll');
bodyStyle.setProperty('width', '100%');
bodyStyle.setProperty('top', `-${currentY}px`);
};
const enableScroll = () => {
events.forEach((event) => {
window.removeEventListener(event, preventDefault);
});
const bodyStyle = document.body.style;
bodyStyle.removeProperty('touch-action');
bodyStyle.removeProperty('position');
bodyStyle.removeProperty('overflow-y');
bodyStyle.removeProperty('width');
bodyStyle.removeProperty('top');
window.scroll(0, currentY);
};
/**
* Makes a component (e.g. popup) modal
*/
export const makeModal = () => {
if (process.client) {
disableScroll();
}
};
/**
* Makes a component (e.g. popup) non-modal
*/
export const makeNonModal = () => {
if (process.client) {
enableScroll();
}
};
我读的大多数答案都是关于React的。
我的React功能组件的最佳解决方案是使用@arcticmatt最初提供的解决方案
我在下面的代码示例中包含了一些在其他答案中提到的改进(注意useEffect定义):
import {useEffect, useRef} from "react";
export default function PopoverMenu({className, handleClose, children}) {
const selfRef = useRef(undefined);
useEffect(() => {
const isPopoverOpenned = selfRef.current?.style.display !== "none";
const focusedElement = document?.activeElement;
const scrollPosition = {x: window.scrollX, y: window.scrollY};
if (isPopoverOpenned) {
preventDocBodyScrolling();
} else {
restoreDocBodyScrolling();
}
function preventDocBodyScrolling() {
const width = document.body.clientWidth;
const hasVerticalScrollBar = (window.innerWidth > document.documentElement.clientWidth);
document.body.style.overflowX = "hidden";
document.body.style.overflowY = hasVerticalScrollBar ? "scroll" : "";
document.body.style.width = `${width}px`;
document.body.style.position = "fixed";
}
function restoreDocBodyScrolling() {
document.body.style.overflowX = "";
document.body.style.overflowY = "";
document.body.style.width = "";
document.body.style.position = "";
focusedElement?.focus();
window.scrollTo(scrollPosition.x, scrollPosition.y);
}
return () => {
restoreDocBodyScrolling(); // cleanup on unmount
};
}, []);
return (
<>
<div
className="backdrop"
onClick={() => handleClose && handleClose()}
/>
<div
className={`pop-over-menu${className ? (` ${className}`) : ""}`}
ref={selfRef}
>
<button
className="pop-over-menu--close-button" type="button"
onClick={() => handleClose && handleClose()}
>
X
</button>
{children}
</div>
</>
);
}