在实现弹窗效果时通常我们都不希望浏览器还能继续滚动,特别是当弹窗里也有滚动条的时候,有双层滚动条的效果及体验都是极差的。
锁定页面的原理:
- 设置
<body>
标签的样式为overflow: hidden
- 给
<body>
标签添加一个值为滚动条宽度的padding-right
代码实现:
function lockScroll () {
let body = document.body;
// 记录了锁定滚动条之前body的属性,以便在解锁后恢复锁定前的样式
let originBodyOverflow = body.style.overflow;
let originBodyPaddingRight = body.style.paddingRight;
let originBodyPaddingBottom = body.style.paddingBottom;
let originBodyHasLockClass = body.classList.contains('bs-lock-scroll');
let hasScroll = hasScroll();
let scrollWidth = scrollWidth();
// 标记本次是否锁定了页面
let locked = false;
if (!originBodyHasLockClass) {
body.classList.add('bs-lock-scroll');
}
if (originBodyOverflow != 'hidden') {
body.style.overflow = 'hidden';
locked = true;
if (hasScroll.vertical) {
body.style.paddingRight = scrollWidth.vertical + 'px';
}
if (hasScroll.horizontal) {
body.style.paddingBottom = scrollWidth.horizontal + 'px';
}
}
// 返回一个解除锁定滚动条的函数
return function () {
let body = document.body;
if (!originBodyHasLockClass) {
body.classList.remove('bs-lock-scroll');
}
if (!locked) {
return;
}
if (originBodyOverflow) {
body.style.overflow = originBodyOverflow;
} else {
body.style.overflow = ''; // 移除body上的overflow属性
}
if (originBodyPaddingRight && parseFloat(originBodyPaddingRight) !== scrollWidth.vertical) {
body.style.paddingRight = originBodyPaddingRight;
} else {
body.style.paddingRight = ''; // 移除body上的paddingRight属性
}
if (originBodyPaddingBottom && parseFloat(originBodyPaddingBottom) !== scrollWidth.horizontal) {
body.style.paddingBottom = originBodyPaddingBottom;
} else {
body.style.paddingBottom = ''; // 移除body上的paddingBottom属性
}
};
};
/**
* 获取元素或浏览器滚动条的宽高
* @param ele dom元素
* @returns {{horizontal: number, vertical: number}}
*/
function scrollWidth (ele) {
var tempDiv;
var tempInnerDiv = document.createElement('div');
var result = {
vertical: 0,
horizontal: 0
};
tempInnerDiv.style.cssText = 'width: 200px;height: 200px';
if (!ele || ele.nodeType != 1) { // 未传递dom元素则获取浏览器的滚动条
result.vertical = window.innerWidth - document.documentElement.offsetWidth;
result.horizontal = window.innerHeight - document.documentElement.clientHeight;
return result;
}
tempDiv = ele.cloneNode(true);
tempDiv.style.cssText = 'width: 100px;height: 100px;opacity: 0;position:absolute;left: -100px;overflow:auto;';
tempDiv.appendChild(tempInnerDiv);
document.body.appendChild(tempDiv);
result.vertical = tempDiv.offsetWidth - tempDiv.clientWidth;
result.horizontal = tempDiv.offsetHeight - tempDiv.clientHeight;
document.body.removeChild(tempDiv);
tempDiv = tempInnerDiv = null;
return result;
}
/**
* 判断浏览器或dom元素是否有滚动条
* @returns {{horizontal: boolean, vertical: boolean}}
*/
function hasScroll () {
return {
vertical: document.body.scrollHeight > window.innerHeight,
horizontal: document.body.scrollWidth > window.innerWidth
};
}
使用:
var unLock = lockScroll();
// 解锁
// unLock();
效果(多次调用锁定):
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。