使“scrollLeft”/“scrollTop”更改不触发滚动事件监听器
Posted
技术标签:
【中文标题】使“scrollLeft”/“scrollTop”更改不触发滚动事件监听器【英文标题】:Make "scrollLeft" / "scrollTop" changes not trigger scroll event listener 【发布时间】:2010-11-26 01:55:57 【问题描述】:目前我的程序处于一个位置,它既可以监听用户滚动某个元素,又有时会自动滚动该元素。 (不是一个渐进的、漂亮的滚动,而是一个瞬间的跳跃。我发誓,这在上下文中是有道理的。)
如果通过设置 scrollLeft 或 scrollTop 完成滚动,有没有办法使滚动事件不触发?我的第一个想法是一个基本的开关,比如:
ignoreScrollEvents = true;
element.scrollLeft = x;
ignoreScrollEvents = false;
function onScroll()
if(ignoreScrollEvents) return false;
但由于事件不会立即触发(哎呀,duhh),这不是一个可行的解决方案。我可以尝试什么其他类型的答案?我也在使用 jQuery,如果有帮助的话。
【问题讨论】:
【参考方案1】:最简单的通用方法?只需在事件处理程序中重置标志。您需要先检查您是否真的在更改值,否则不会触发事件 - 如Rodrigo notes,这里的一个好做法是将其分解为所谓的“setter”函数:
function setScrollLeft(x)
if ( element.scrollLeft != x )
ignoreScrollEvents = true;
element.scrollLeft = x;
...
function onScroll()
var ignore = ignoreScrollEvents;
ignoreScrollEvents = false;
if (ignore) return false;
...
但是,根据您的需要,您可能已经将滚动位置存储在某处;如果是这样,只需更新并检查它作为您的标志。比如:
element.scrollLeft = currentScrollLeft = x;
...
function onScroll()
// retrieve element, etc...
if (element.scrollLeft == currentScrollLeft) return false;
...
【讨论】:
在我的代码中,我遇到了一个问题:有时会发生,例如 scrollLeft 已经为 0,然后我的代码也将其设置为 0。因此,没有触发滚动事件,并且下一个用户滚动被忽略。 (如果他们使用 Home、End 等滚动,这才是真正的问题。)但这绝对是一个接近的解决方案 - 我知道我在那个虚拟实现中遗漏了一些愚蠢的东西。谢谢! 我想知道...那么您最好的选择是在设置标志之前检查您是否更改了值 - 如果不是,请不要设置它。您可能已经将此代码分解为一个单独的函数,但如果没有,那么这样做会更容易 - 有关此示例,请参阅 Rodrigo 的答案。【参考方案2】:二传手怎么样?
var _preventEvent = false; // set global flag
function setScrollTop(amount)
_preventEvent = true; // set flag
document.documentElement.scrollTop = amount * Math.random();
function setScrollLeft(amount)
_preventEvent = true; // set flag
document.documentElement.scrollLeft = amount * Math.random();
// scroll event listener
window.onscroll = function()
console.clear();
if (_preventEvent)
_preventEvent = false; // reset flag
return;
console.log('normal scroll');
html height:500%; width:500%;
button position:fixed;
button + button top:50px;
<button onclick=setScrollTop(1000)>Random scrollTop</button>
<button onclick=setScrollLeft(1000)>Random scrollLeft</button>
【讨论】:
【参考方案3】:您可以尝试存储元素的偏移顶部,并在您进入 onScroll 时将其与 scrollTop 匹配:
function onScroll()
var scrollTop = (document.documentElement.scrollTop || document.body.scrollTop),
offsetTop = $('selector').offset().top;
if(offsetTop > scrollTop)
//user has not scrolled to element so do auto scrolling
【讨论】:
【参考方案4】:好吧,我的最终解决方案,基于 Shog9(不是我的真实代码,而是我的方法):
var oldScrollLeft = element.scrollLeft;
element.scrollLeft = x;
if(element.scrollLeft != oldScrollLeft)
ignoreScrollEvents = true;
function onScroll()
if(!ignoreScrollEvents) performGreatActions();
ignoreScrollEvents = false;
if 语句仅在 scrollLeft 值实际最终发生变化时设置忽略标志,因此从 0 设置为 0 等情况不会错误设置标志。
谢谢大家!
【讨论】:
不确定。这里有什么协议?如果我使用部分答案,然后将其构建以达到完整答案,我是标记自己的还是其他的? 已接受的答案已被编辑以包含此警告,因此它现在与此答案匹配 :) 酷!以上是关于使“scrollLeft”/“scrollTop”更改不触发滚动事件监听器的主要内容,如果未能解决你的问题,请参考以下文章
jQuery 源码解析(二十八) 样式操作模块 scrollLeft和scrollTop详解
scrollTop 和 scrollLeft 在 display:none 元素上不起作用
JQUERY中的scrollTop 和scrollleft到底是啥意思
使用动画链(jQuery)在 Ipad 上的 ScrollLeft 和 ScrollTop
使用 -webkit-overflow-scrolling:touch - Safari iOS javascript 事件 (scrollTop / scrollLeft) 时的当前滚动位置