关于javascript:js锁定浏览器滚动条锁定页面

27次阅读

共计 2565 个字符,预计需要花费 7 分钟才能阅读完成。

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

锁定页面的原理:

  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();

成果(屡次调用锁定):

正文完
 0