vueAnt中modal滚动条导致偏移处理方法

 新闻资讯     |      2021-01-29 17:14:07

modal对话框是非常好用的一款弹出层组件,受众也非常广泛。

modal框的特点

modal在打开时会隐藏真实的滚动条。将body变成不可滚动状态。

当modal的内容超长,会使用遮罩层的滚动条,而不是body。
注意观察




好处非常明显,
1.禁止使用者随意滚动界面,视角专注于弹窗本身
2.当modal窗内容超出窗口高度是,可以使用遮罩层本身的滚动条,同时更好的利用窗口

但是从有滚动条到没有滚动条,页面元素肯定是会发生偏移的。
组件本身为了避免这个问题做了一些处理。
在需要处理的时候,对body增加了一个内边距,是滚动条的宽度:

在某些情况下,这并不能完全避免元素偏移。
我们有时候会对导航条或一些元素做吸顶效果。也就是页面上有fixed元素。
这些元素是脱离流布局的,body的padding-right属性不能让他们其效果,这就造成了错位。
需要针对fixed元素进行单独处理。我们在给body加上pdding-right的同时,也要给fixed元素加上一个边距效果。以保证
fixed元素不移动位置
在这里我给body加上class以便统一处理。


 

上代码:

主要关注源码,获取滚动条的宽度(注意一下每个浏览器的滚动条宽度都不一定先相同):

var cached = void 0;

export default function getScrollBarSize(fresh) {
  if (fresh || cached === undefined) {
    var inner = document.createElement('div');
    inner.style.width = '100%';
    inner.style.height = '200px';

    var outer = document.createElement('div');
    var outerStyle = outer.style;

    outerStyle.position = 'absolute';
    outerStyle.top = 0;
    outerStyle.left = 0;
    outerStyle.pointerEvents = 'none';
    outerStyle.visibility = 'hidden';
    outerStyle.width = '200px';
    outerStyle.height = '150px';
    outerStyle.overflow = 'hidden';

    outer.appendChild(inner);

    document.body.appendChild(outer);

    var widthContained = inner.offsetWidth;
    outer.style.overflow = 'scroll';
    var widthScroll = inner.offsetWidth;

    if (widthContained === widthScroll) {
      widthScroll = outer.clientWidth;
    }

    document.body.removeChild(outer);

    cached = widthContained - widthScroll;
  }
  return cached;
}

判断当前页面是否有滚动条:

checkScrollbar: function checkScrollbar() {
      var fullWindowWidth = window.innerWidth;
      if (!fullWindowWidth) {
        // workaround for missing window.innerWidth in IE8
        var documentElementRect = document.documentElement.getBoundingClientRect();
        fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left);
      }
      this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth;
      if (this.bodyIsOverflowing) {
        this.scrollbarWidth = getScrollBarSize();
      }
    },

当弹窗打开后,设置页面的内间距和class(class为了处理少部分fixed元素,思路为css优先级

setScrollbar: function setScrollbar() {//TODO EDIT
      if (this.bodyIsOverflowing && this.scrollbarWidth !== undefined) {
        document.body.style.paddingRight = this.scrollbarWidth + 'px';
        document.body.classList.add('modal-scrollbar');
      }
    },


resetScrollbar: function resetScrollbar() {
      document.body.style.paddingRight = '';
      document.body.classList.remove('modal-scrollbar')//TODO EDIT
    },

样式处理,这里的17PX是和this.scrollbarWidth相同的,需要完善

//专门为了处理modal打开后元素浮动的问题
.modal-scrollbar {
  .zff-header {
    padding-right17px;
  }
  .qidian_wpa_img {
    margin-right17px;
  }
}