在实现弹窗成果时通常咱们都不心愿浏览器还能持续滚动,特地是当弹窗里也有滚动条的时候,有双层滚动条的成果及体验都是极差的。
锁定页面的原理:
- 设置
<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();
成果(屡次调用锁定):