Javascript 确定捕捉滚动元素';s的快照滚动事件已完成 摘要

Javascript 确定捕捉滚动元素';s的快照滚动事件已完成 摘要,javascript,css,animation,easing,scroll-snap,Javascript,Css,Animation,Easing,Scroll Snap,我正在使用可滚动元素创建图像库。我正在使用CSS的滚动捕捉功能,它允许我捕捉滚动条中的元素(图像) function scrollHandler(e) { var atSnappingPoint = e.target.scrollLeft % e.target.offsetWidth === 0; var timeOut = atSnappingPoint ? 0 : 150; //see notes clearTimeout(e.target.scro

我正在使用可滚动元素创建图像库。我正在使用CSS的滚动捕捉功能,它允许我捕捉滚动条中的元素(图像)

function scrollHandler(e) {
    var atSnappingPoint = e.target.scrollLeft % e.target.offsetWidth === 0;
    var timeOut         = atSnappingPoint ? 0 : 150; //see notes

    clearTimeout(e.target.scrollTimeout);
    e.target.scrollTimeout = setTimeout(function() {
        console.log('Scrolling is done!');
    }, timeOut);
}

myElement.addEventListener('scroll', scrollHandler);
通过绑定到元素的
scroll
事件,我可以在用户滚动元素时应用各种操作(比如预加载、隐藏界面元素等)。其中之一取决于滚动事件,需要在滚动完成时停止。但卷轴抓拍给我带来了一个无法预料但却无法处理的局面

我无法准确确定快照滚动操作是否完成。

我可以在每个滚动上设置一个
setTimeout
,它会自动取消并重新设置(有效地消除抖动),如果不重置,最终会被调用。但设置此选项时使用的超时可能意味着您在确定是否完成滚动时“太晚了”

底线:我如何检查滚动是否完成,因为:

  • 用户已停止滚动,或
  • 滚动条已到达其捕捉点(
    scroll snap type
    已设置)

  • 我终于,明确地,解决了这个脑筋急转弯。这比我原来想象的要简单得多。 (注意:在我的例子中,它适用于水平滚动条;在本例中,将
    offsetWidth
    更改为
    offsetHeight
    并将
    scrollLeft
    更改为
    scrollTop
    ,以适应垂直滚动条。)

    崩溃 通过使用滚动元素自身的width(或垂直滚动时的高度),我们可以通过将元素的滚动位置(
    scrollLeft
    在我的情况下)除以其宽度(
    offsetWidth
    )来计算它是否达到了捕捉点,如果这产生了一个整数(意思是:宽度正好与滚动位置“匹配”x倍)它已到达捕捉点。我们使用:

    然后,如果达到捕捉点,则将
    超时设置为0(在滚动完成时应触发的
    设置超时中使用)。否则,使用常规值(在上面的示例150中,请参阅注释)

    这是因为当元素实际到达其捕捉点时,最后一个
    scroll
    事件被触发,我们的处理程序(再次)被触发。将
    timeOut
    调整为0将立即调用我们的超时函数;因此当滚动器“点击”捕捉点时,我们立即知道这一点


    笔记 在捕捉点上滚动我还没有实现/考虑到这样一个事实,即可以通过滚动捕捉点来“命中”捕捉点。但这是非常罕见的。我会在找到解决方案后更新答案

    像素比率:如果计算出错(1像素的剩余部分等,因此函数无法正确解析),则可能存在一些缩放/框模型问题,从而导致滚动位置和偏移宽度计算的计算出错。 这很可能是由设备的像素比率引起的,因此您可以尝试通过将这些值乘以像素比率来“纠正”这些值(向左滚动和宽度)。 重要提示:事实证明,像素比率不仅指示用户是否具有高dpi屏幕,而且在用户缩放页面时也会发生变化

    timeout当滚动尚未达到捕捉点时,使用的任意
    timeout
    为150。这足够长,可以防止在Safari@iOS完成滚动之前触发它(它使用贝塞尔曲线进行滚动捕捉,产生大约120-130ms的非常长的“最后一帧”)并且足够短,当用户在捕捉点之间暂停滚动时,可以产生可接受的结果

    滚动填充如果已在滚动元素上设置了
    滚动填充
    ,则在确定捕捉点时需要将其考虑在内

    剩余像素数:您甚至可以进一步细分,以在到达捕捉点之前计算剩余像素数:

    var pxRemain = e.target.scrollLeft % e.target.offsetWidth;
    var atSnappingPoint = pxRemain === 0;
    
    但请注意,您需要从元素的宽度中减去该值,具体取决于您滚动的方式。这需要您计算滚动的距离,并检查该距离是负值还是正值。然后它将变为:

    var pxRemain = e.target.scrollLeft % e.target.offsetWidth;
        pxRemain = (pxRemain === 0) ? 0 : ((distance > 0) ? pxRemain : elementWidth - pxRemain);
    var atSnappingPoint = pxRemain === 0;
    
    只会折断 编写此脚本时考虑了两种情况:

  • 元素已捕捉到其捕捉点,或
  • 用户已暂停滚动(或捕捉检测不知何故出错)
  • 如果只需要前者,则不需要超时,只需编写:

    function scrollHandler(e) {
      if (e.target.scrollLeft % e.target.offsetWidth === 0) {
        console.log('Scrolling is done!');
      }
    }
    
    myElement.addEventListener('scroll', scrollHandler);
    
    function scrollHandler(e) {
      if (e.target.scrollLeft % e.target.offsetWidth === 0) {
        console.log('Scrolling is done!');
      }
    }
    
    myElement.addEventListener('scroll', scrollHandler);