Javascript 当窗口垂直滚动条出现时检测
是否有一个简单可靠的解决方案来检测窗口垂直滚动条的出现/消失 当JavaScriptDOM操作后页面变高到足以显示滚动条时,不会触发Javascript 当窗口垂直滚动条出现时检测,javascript,jquery,resize,scrollbar,Javascript,Jquery,Resize,Scrollbar,是否有一个简单可靠的解决方案来检测窗口垂直滚动条的出现/消失 当JavaScriptDOM操作后页面变高到足以显示滚动条时,不会触发window.onresize 在这篇非常类似的文章中,我描述了如何检测滚动条是否存在,但我需要知道它的确切出现时间。很抱歉,让我死而复生,但我刚刚遇到了这个限制,并提出了我自己的解决方案。这有点老套,但还是跟着我 其想法是在页面上添加一个100%宽度的不可见iframe,并在其内部窗口上侦听调整大小事件。这些事件不仅会拾取外部窗口大小的更改,还会在外部窗口中添加或
window.onresize
在这篇非常类似的文章中,我描述了如何检测滚动条是否存在,但我需要知道它的确切出现时间。很抱歉,让我死而复生,但我刚刚遇到了这个限制,并提出了我自己的解决方案。这有点老套,但还是跟着我 其想法是在页面上添加一个100%宽度的不可见iframe,并在其内部窗口上侦听调整大小事件。这些事件不仅会拾取外部窗口大小的更改,还会在外部窗口中添加或删除滚动条时拾取更改 它会触发一个常规的窗口大小调整事件,所以如果您已经在侦听窗口大小调整,则不需要额外的代码 在IE9和Chrome/Firefox最新版本中测试-可能在旧版IEs中工作,但我的项目不支持这些,所以我没有尝试过
根据Panda的回答,他想出了这个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');
$('').css({
'位置':'固定',
“宽度”:“100%”,
“高度”:0,
“底部”:0,
“边框”:0,
“背景色”:“透明”
}).on('load',function()){
var vsb=(document.body.scrollHeight>document.body.clientHeight);
var定时器=null;
this.contentWindow.addEventListener('resize',function()){
清除超时(计时器);
计时器=设置超时(函数(){
var vsbnew=(document.body.scrollHeight>document.body.clientHeight);
if(vsbnew){
如果(!vsb){
$(top.window).trigger('scrollbar',[true]);
vsb=真;
}
}否则{
中频(vsb){
$(top.window).trigger('scrollbar',[false]);
vsb=假;
}
}
}, 100);
});
}).附于(“主体”);
这将触发窗口上的“滚动条”事件(如果出现/消失)
至少可以在chrome/mac上使用。现在,有人扩展它来检测水平滚动条:-)动态检测浏览器垂直滚动条事件 正在将window.innerWidth与getBoundingClientRect()进行比较 使用Javascript创建一个DIV元素。使用最新版本进行测试
IE FF铬合金。请参阅文档如果您使用的是AngularJS,则可以使用指令来检测宽度何时更改(假设出现/消失的滚动条是垂直的): 这将在根作用域上激发一个事件,其他指令或控制器可以侦听该事件 手表由angular digest循环触发,因此这取决于angular是否加载/删除了导致滚动条出现/消失的额外内容。 通过使用
ResizeObserver
检查可能占用滚动条的元素大小的变化及其内容大小的变化,可以检测滚动条可见性的变化
根本原因
我开始用
方法实现一个解决方案,但很快发现要实现一个完整的解决方案,需要打破应用程序视图之间的关注点分离。我有一个父视图,它需要知道子视图何时获得垂直滚动条。(我不关心水平滚动条。)我有两种情况可能会影响垂直滚动条的可见性:
,我将不得不修改子视图以支持父视图的需要。我希望孩子不包含纯粹是家长关心的东西的代码。使用我在这里描述的解决方案,只需要修改父视图
因此,在寻找更好的解决方案时,我找到了Daniel Herr。他建议使用ResizeObserver
来检测div的维度何时发生变化ResizeObserver
还不能在浏览器中以本机方式提供,但在本机支持不可用的情况下,我会使用强大的ponyfill/polyfill来提供支持。(以下是针对ResizeObserver
的示例)
概念证明
我在它的ponyfill模式下使用。这样,全球环境就不会受到影响。此实现依赖于window.requestAnimationFrame
,对于不支持window.requestAnimationFrame
的平台,将依赖于setTimeout
。看着“我能用…?”上的文字,我看到的并没有困扰我。YMMV
我有一个活的。关键是监听可以接受滚动条的DOM元素(id为容器的元素,绿色)的大小变化,以及监听可能需要滚动的内容(id为内容的元素)的大小变化。概念验证使用interact.js
来管理一个resizer元素(idresizer
,蓝色),该元素允许调整容器的大小。如果拖动大小调整器的右下角,它将同时调整大小调整器和容器的大小。这两个按钮允许模拟容器显示的内容大小的变化
我在目前处于预发布阶段的代码中使用此方法,这意味着它通过了多个浏览器上的测试,并且正在由涉众进行评估,但尚未投入生产
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>
这一切都是关于何时需要确定滚动条的可见性
OP提到了一个时间“在JavaScript DOM manipula之后”
<!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>
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);
* {
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;
}