检测窗口垂直滚动条何时出现

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了检测窗口垂直滚动条何时出现相关的知识,希望对你有一定的参考价值。

是否有一个简单可靠的解决方案来检测窗口垂直滚动条出现/消失?

javascript DOM操作页面变得足够高以显示滚动条之后,不会触发window.onresize

在这个非常相似的帖子中,Detect if a page has a vertical scrollbar描述了如何检测滚动条是否存在的解决方案,但我需要知道它何时出现。

答案

Window.onresize无法正常工作,因为窗口没有调整大小。

body.onresize不起作用,因为resize仅适用于窗户和框架。

This question处理同样的问题。顶级回答者有一些有趣的想法,虽然不是简单的,或跨浏览器。

我认为Rick Strahl基于Jquery的方法是你能得到的最好的方法:Monitoring Html Element CSS Changes in JavaScript它使用浏览器的“监视”功能(如果可用),或者如果没有则使用计时器。后者不是非常资源友好,但似乎没有办法解决它。

顺便说一句resize解决后如何告诉滚动条的一个好方法是在this question顺便说一句,以防你在你的问题中没有提到那个。

另一答案

很抱歉从死里复活,但我刚刚遇到这个限制并提出了我自己的解决方案。这有点hacky但坚持我...

我们的想法是向页面添加100%宽度的不可见iframe,并在其内部窗口上侦听resize事件。这些事件不仅会对外部窗口的大小进行更改,还会在外部窗口中添加或删除滚动条时进行更改。

它会触发常规窗口调整大小事件,因此如果您已经在侦听窗口大小调整,则不需要额外的代码。

在IE9和Chrome / Firefox最新测试 - 也许可以在旧的IE中工作,但我的项目不支持那些,所以我没有尝试过。

https://gist.github.com/OrganicPanda/8222636

另一答案

根据OrganicPanda的回答,提出了这个jquery的事情

$('<iframe id="scrollbar-listener"/>').css({
    'position'      : 'fixed',
'width'         : '100%',
'height'        : 0, 
'bottom'        : 0,
'border'        : 0,
'background-color'  : 'transparent'
}).on('load',function() {
    var vsb     = (document.body.scrollHeight > document.body.clientHeight);
    var timer   = null;
    this.contentWindow.addEventListener('resize', function() {
        clearTimeout(timer);
        timer = setTimeout(function() {
            var vsbnew = (document.body.scrollHeight > document.body.clientHeight);
            if (vsbnew) {
                if (!vsb) {
                    $(top.window).trigger('scrollbar',[true]);
                    vsb=true;
                }
            } else {
                if (vsb) {
                    $(top.window).trigger('scrollbar',[false]);
                    vsb=false;
                }
            }
        }, 100);
    });
}).appendTo('body');

这将触发窗口上的“滚动条”事件,如果它们出现/消失

至少可以在chrome / mac上使用。现在,有人扩展此检测水平滚动条:-)

另一答案

如果您正在使用AngularJS,则可以使用指令来检测宽度何时更改(假设出现/消失的滚动条是垂直滚动条):

app.directive('verticalScroll', function($rootScope){
    return {
        restrict: 'A',
        link: function (scope, element) {
            scope.$watch(
                function() {
                    return element[0].clientWidth;
                },
                function() {
                    $rootScope.$emit('resize');
                }
            );
        }
    }
});

这将触发根范围上的事件,其他指令或控制器可以侦听该事件。

手表由角度消化循环触发,因此这依赖于Angular加载/删除了导致滚动条出现/消失的额外内容。

另一答案

The Scoop

通过使用ResizeObserver检查可能占用滚动条的元素大小的变化以及其内容大小的变化,可以检测滚动条可见性的变化。

Rationale

我开始使用<iframe>方法实现一个解决方案,但很快发现有一个完整的实现需要打破我的应用程序视图之间的关注点分离。我有一个父视图,需要知道子视图何时获取垂直滚动条。 (我不关心水平滚动条。)我有两种情况可能会影响垂直滚动条的可见性:

  1. 父视图已调整大小。这是由用户直接控制的。
  2. 子视图的内容变得更大或更小。这是在用户的间接控制下。子视图显示搜索结果。结果的数量和类型决定了子视图的大小。

我发现,如果我使用<iframe>,我必须用子视图来支持父母的需要。我更喜欢孩子不包含纯粹父母关心的东西的代码。使用我在此描述的解决方案,只需要修改父视图。

因此,在寻找更好的解决方案时,我找到了Daniel Herr的this answer。他建议使用ResizeObserver来检测div的尺寸何时发生变化。 ResizeObserver尚未在浏览器中本地提供,但有一个强大的ponyfill / polyfill,我用它来支持原生支持不可用的情况。 (这是specResizeObserver。)

Proof-of-Concept

我在其ponyfill模式下使用this polyfill。这样,全球环境仍未受到影响。这种实现依赖于window.requestAnimationFrame,并且对于不支持setTimeout的平台将依赖于window.requestAnimationFrame。看看support for requestAnimationFrame“我能用......吗?”,我看到的并没有打扰我。因人而异。

我有一个活的proof-of-concept。关键是要听DOM元素上的大小变化,它可以接受滚动条(id为container的元素,绿色),并听取可能需要滚动的内容(id为content的元素)的大小变化。概念验证使用interact.js来管理resizer元素(id为resizer,蓝色),允许调整container的大小。如果你拖动resizer的右下角,它将调整resizercontainer的大小。这两个按钮允许模拟container显示的内容大小的变化。

我在目前处于预发布阶段的代码中使用此方法,这意味着它在多个浏览器上通过了测试,并且正在由利益相关者进行评估,但尚未投入生产。

html

<!DOCTYPE html>
<html>

<head>
  <script data-require="interact.js@*" data-semver="1.0.26" src="//rawgit.com/taye/interact.js/v1.0.26/interact.js"></script>
  <script src="//rawgit.com/que-etc/resize-observer-polyfill/master/dist/ResizeObserver.global.js"></script>
  <link rel="stylesheet" href="style.css" />
</head>

<body>
  <div id="resizer">
    <div id="container">
      <ul id="content">
        <li>Something</li>
      </ul>
    </div>
  </div>
  <button id="add">Add to content</button>
  <button id="remove">Remove from content</button>
  <p>Scroll bar is: <span id="visibility"></span></p>
  <ul id="event-log"></ul>
  <script src="script.js"></script>
</body>

</html>

JavaScript:

var container = document.getElementById("container");
var resizer = document.getElementById("resizer");
interact(resizer)
  .resizable({
    restrict: {
      restriction: {
        left: 0,
        top: 0,
        right: window.innerWidth - 10,
        bottom: window.innerHeight - 10
      }
    }
  })
  .on('resizemove', function(event) {
    var target = resizer;

    var rect = target.getBoundingClientRect();

    var width = rect.width + event.dx;
    var height = rect.height + event.dy;
    target.style.width = width + 'px';
    target.style.height = height + 'px';
  });

var content = document.getElementById("content");
var add = document.getElementById("add");
add.addEventListener("click", function() {
  content.insertAdjacentHTML("beforeend", "<li>Foo</li>");
});

var remove = document.getElementById("remove");
remove.addEventListener("click", function() {
  content.removeChild(content.lastChild);
});

// Here is the code that pertains to the scrollbar visibility

var log = document.getElementById("event-log");
content.addEventListener("scrollbar", function () {
  log.insertAdjacentHTML("beforeend", "<li>Scrollbar changed!</li>");
});

var visiblity = document.getElementById("visibility");
var previouslyVisible;
function refreshVisibility() {
  var visible = container.scrollHeight > container.clientHeight;
  visibility.textContent = visible ? "visible" : "not visible";
  if (visible !== previouslyVisible) {
    content.dispatchEvent(new Event("scrollbar"));
  }
  previouslyVisible = visible;
}
// refreshVisibility();


var ro = new ResizeObserver(refreshVisibility);
ro.observe(container);
ro.observe(content);

CSS:

* {
  box-sizing: border-box;
}

#container {
  position: relative;
  top: 10%;
  left: 10%;
  height: 80%;
  width: 80%;
  background: green;
  overflow: auto;
}

#resizer {
  background: blue;
  height: 200px;
  width: 200px;
}
另一答案

这一切都与您需要确定滚动条可见性有关。

OP谈到“在JavaScript DOM操作

以上是关于检测窗口垂直滚动条何时出现的主要内容,如果未能解决你的问题,请参考以下文章

检测滚动条何时到达div的顶部?

使边框环绕整个窗口会导致显示垂直滚动条? [复制]

jquery如何获取元素的滚动条高度等实现代码

在不影响浏览的情况下隐藏垂直的滚动条的方法都有哪些?

Bootstrap:如何禁用垂直滚动条?

居中 div 中垂直滚动条覆盖的内容的右边缘