在实现弹窗成果时通常咱们都不心愿浏览器还能持续滚动,特地是当弹窗里也有滚动条的时候,有双层滚动条的成果及体验都是极差的。

锁定页面的原理:

  1. 设置<body>标签的款式为overflow: hidden
  2. <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();

成果(屡次调用锁定):