【问题标题】:Scroll event listener javascript滚动事件监听器 javascript
【发布时间】:2012-09-13 10:05:24
【问题描述】:

当用户在某个可以使用的文本框中滚动时,是否有一个 js 监听器?有点像 onclick 除了滚动。我看到了HTML5 event listener for number input scroll - Chrome only,但这似乎只适用于 chrome。我正在寻找跨浏览器的东西。

【问题讨论】:

标签: javascript


【解决方案1】:

对于那些发现这个问题并希望找到不涉及 jQuery 的答案的人,您可以使用普通的事件侦听钩入 window "scroll" 事件。假设我们要添加滚动监听许多 CSS-selector-able 元素:

// what should we do when scrolling occurs
function runOnScroll(element) {
  // not the most exciting thing, but a thing nonetheless
  console.log(element);
};

// grab elements as array, rather than as NodeList
const elements = document.querySelectorAll(`...`);

// and then make each element do something on scroll
elements.forEach(element => {
  window.addEventListener(
    "scroll",
    () => runOnScroll(element),
    { passive: true }
  );
});

或者,也可以绑定一个滚动侦听器,将evt => runOnScroll(evt) 作为处理程序,然后在runOnScroll 函数中找出如何处理elements 中的所有内容。

请注意,我们使用passive 属性告诉浏览器此事件不会干扰滚动本身。如果我们想要平滑的滚动行为,这一点很重要(也意味着我们不应该在滚动期间执行触发回流的 DOM 更新)。

对于奖励积分,您可以为滚动处理程序提供锁定机制,以便在我们已经滚动时它不会运行:

// global lock, so put this code in a closure of some sort so you're not polluting.
let locked = false;
let lastCall = false;

function runOnScroll(element) {
  if(locked) return;

  if (lastCall) clearTimeout(lastCall);
  lastCall = setTimeout(() => {
    runOnScroll(element);
    // you do this because you want to handle the last
    // scroll event, even if it occurred while another
    // event was being processed.
  }, 200);

  // ...your code goes here...

  locked = false;
};

【讨论】:

  • 只是好奇 - 不确定它是否重要 - 但是 useCapture 应该为滚动事件侦听器返回 false 还是 true?
  • 没关系 - 设置 useCapture 是一种确保在任何处理程序由于冒泡或“我不关心它被调用的顺序”而导致事件之前触发处理程序的方法设置useCapture。但是,这并不太有用,因为当使用多个带有useCapture=true 的侦听器时,没有调用顺序保证。
  • 非常干净,但是这不会破坏滚动性能,因为我们在滚动时添加了一个监听器,无论我们选择多少元素?我认为我们希望集中 onScroll 逻辑,以便我们可以管理执行的内容。你发现了什么?
  • 非常好,所以为了提高性能,你可以把它变成一个标准的“事件监听器只设置一个标志”(其中“标志”只是滚动目标值),具有独立调度的“句柄滚动数据“您在超时时调用的函数(如果它没有运行,scroll 事件将启动它,如果它已经运行,如果它没有看到要处理的新滚动数据,它会取消它的运行)。
  • 关于锁定的真/假检查:代码不会只触发一次(用户第一次滚动)吗??
【解决方案2】:

以下基本方法不能满足您的要求吗?

具有 div 的 HTML 代码

<div id="mydiv" onscroll='myMethod();'>


JS 会有以下代码

function myMethod(){ alert(1); }

【讨论】:

  • 从狭义上讲,这是function,而不是method :-)
  • 这取决于 myMethod 是否是全局的 - window.myMethod ;)。
【解决方案3】:

我一直在寻找使用老式 JS(没有 JQuery)的 sticy menue 的解决方案。所以我建立了一个小测试来玩它。我认为这对那些在 js 中寻找解决方案的人会有所帮助。 它需要改进使菜单背面不粘,并使其更光滑。 我还找到了一个使用 JQuery 的不错的解决方案,它可以克隆原始 div 而不是固定位置,它更好,因为在修复后不需要替换页面元素的其余部分。任何人都知道如何使用 JS 吗? 请备注、指正、改进。

<!DOCTYPE html>
<html>

<head>
<script>

// addEvent function by John Resig:
// http://ejohn.org/projects/flexible-javascript-events/

function addEvent( obj, type, fn ) {

    if ( obj.attachEvent ) {

        obj['e'+type+fn] = fn;
        obj[type+fn] = function(){obj['e'+type+fn]( window.event );};
        obj.attachEvent( 'on'+type, obj[type+fn] );
    } else {
        obj.addEventListener( type, fn, false );
    }
}
function getScrollY() {
    var  scrOfY = 0;
    if( typeof( window.pageYOffset ) == 'number' ) {
        //Netscape compliant
        scrOfY = window.pageYOffset;

    } else if( document.body && document.body.scrollTop )  {
        //DOM compliant
        scrOfY = document.body.scrollTop;
    } 
    return scrOfY;
}
</script>
<style>
#mydiv {
    height:100px;
    width:100%;
}
#fdiv {
    height:100px;
    width:100%;
}
</style>
</head>

<body>

<!-- HTML for example event goes here -->

<div id="fdiv" style="background-color:red;position:fix">
</div>
<div id="mydiv" style="background-color:yellow">
</div>
<div id="fdiv" style="background-color:green">
</div>

<script>

// Script for example event goes here

addEvent(window, 'scroll', function(event) {

    var x = document.getElementById("mydiv");

    var y = getScrollY();      
    if (y >= 100) {
        x.style.position = "fixed"; 
        x.style.top= "0";
    } 
});

</script>
</body>
</html>

【讨论】:

    【解决方案4】:

    当用户在某个文本框中滚动时,是否有一个可以使用的 js 监听器?

    DOM L3 UI Events 规范给出了初始定义,但 is considered 已过时。

    要添加单个处理程序,您可以这样做:

      let isTicking;
      const debounce = (callback, evt) => {
        if (isTicking) return;
        requestAnimationFrame(() => {
          callback(evt);
          isTicking = false;
        });
        isTicking = true;
      };
      const handleScroll = evt => console.log(evt, window.scrollX, window.scrollY);
      document.defaultView.onscroll = evt => debounce(handleScroll, evt);
    

    对于多个处理程序,或者如果出于样式原因更可取,您可以使用addEventListener,而不是如上所示将您的处理程序分配给onscroll

    如果使用来自 lodash 的 _.debounce 之类的东西,你可能会侥幸成功:

    const handleScroll = evt => console.log(evt, window.scrollX, window.scrollY);
    document.defaultView.onscroll = evt => _.debounce(() => handleScroll(evt));
    

    查看browser compatibility 并确保在完成之前在一些实际设备上进行测试。

    【讨论】:

      【解决方案5】:
      let lastKnownScrollPosition = 0;
      let ticking = false;
      
      function doSomething(scrollPos) {
        // Do something with the scroll position
      }
      
      document.addEventListener('scroll', function(e) {
        lastKnownScrollPosition = window.scrollY;
      
        if (!ticking) {
          window.requestAnimationFrame(function() {
            doSomething(lastKnownScrollPosition);
            ticking = false;
          });
      
          ticking = true;
        }
      });
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-06-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多