jQuery scroll () phát hiện khi nào người dùng ngừng cuộn


109

Ok với cái này ..

$(window).scroll(function()
{
    $('.slides_layover').removeClass('showing_layover');
    $('#slides_effect').show();
});

Tôi có thể biết khi nào ai đó đang cuộn từ những gì tôi hiểu. Vì vậy, với điều đó, tôi đang cố gắng tìm ra cách để bắt khi ai đó dừng lại. Từ ví dụ trên, bạn có thể thấy tôi đang xóa một lớp khỏi một tập hợp các phần tử trong khi cuộn đang diễn ra. Tuy nhiên, tôi muốn đặt lớp đó trở lại khi người dùng ngừng cuộn.

Lý do cho điều này là tôi có ý định có một chương trình chuyển tiếp trong khi trang đang cuộn để tạo cho trang một hiệu ứng đặc biệt mà tôi đang cố gắng thực hiện. Nhưng một lớp mà tôi đang cố gắng loại bỏ trong khi cuộn xung đột với hiệu ứng đó vì nó là hiệu ứng trong suốt đối với một số bản chất.



Tuyệt vời, không trùng lặp chính xác nhưng rõ ràng đã đi đúng hướng về những gì tôi đang tìm kiếm và cuối cùng đã giúp tôi giải quyết vấn đề của mình. Cảm ơn bạn.
chris

Câu trả lời:


253
$(window).scroll(function() {
    clearTimeout($.data(this, 'scrollTimer'));
    $.data(this, 'scrollTimer', setTimeout(function() {
        // do something
        console.log("Haven't scrolled in 250ms!");
    }, 250));
});

Cập nhật

Tôi đã viết một phần mở rộng để nâng cao ontrình xử lý -event mặc định của jQuery . Nó đính kèm một hàm xử lý sự kiện cho một hoặc nhiều sự kiện vào các phần tử đã chọn và gọi hàm xử lý nếu sự kiện không được kích hoạt trong một khoảng thời gian nhất định. Điều này hữu ích nếu bạn muốn kích hoạt một cuộc gọi lại chỉ sau một khoảng thời gian trì hoãn, như sự kiện thay đổi kích thước hoặc tương tự.

Điều quan trọng là phải kiểm tra github-repo để biết các bản cập nhật!

https://github.com/yckart/jquery.unevent.js

;(function ($) {
    var on = $.fn.on, timer;
    $.fn.on = function () {
        var args = Array.apply(null, arguments);
        var last = args[args.length - 1];

        if (isNaN(last) || (last === 1 && args.pop())) return on.apply(this, args);

        var delay = args.pop();
        var fn = args.pop();

        args.push(function () {
            var self = this, params = arguments;
            clearTimeout(timer);
            timer = setTimeout(function () {
                fn.apply(self, params);
            }, delay);
        });

        return on.apply(this, args);
    };
}(this.jQuery || this.Zepto));

Sử dụng nó giống như bất kỳ trình xử lý onhoặc bind-event nào khác , ngoại trừ việc bạn có thể chuyển thêm một tham số vào cuối cùng:

$(window).on('scroll', function(e) {
    console.log(e.type + '-event was 250ms not triggered');
}, 250);

http://yckart.github.com/jquery.unevent.js/

(bản demo này sử dụng resizethay vì scroll, nhưng ai quan tâm ?!)


Nó vẫn không chính xác 100%: đôi khi người dùng ngừng và hồ sơ di chuyển ngay cả sau 250 ms
Arman Bimatov

Mã này hoạt động tuyệt vời, nhưng nó đã phá vỡ hoàn toàn tiện ích tự động điền của jquery ui.
kkazakov

@ArmanBimatov thì nó sẽ được coi là người dùng tiếp tục cuộn, điều này có vẻ tốt, phải không?
godblessstrawberry

Thời gian chờ này chỉ kích hoạt khi các sự kiện cuộn dừng và KHÔNG phải khi người dùng dừng cuộn. Người dùng có thể nhấc ngón tay khỏi chuột và quá trình cuộn có thể tiếp tục trong vài giây tùy thuộc vào tốc độ cuộn của họ. Giải pháp này sẽ không cho bạn biết khi nào người dùng ngừng cuộn.
AndroidDev

1
@abzarak trình trợ giúp trừu tượng này không hoàn hảo, trong mọi trường hợp! Tôi đã không cập nhật github-repo gần đây, vì lý do - đây là một ý tưởng tồi tệ. Thay vào đó, chỉ cần sử dụng chức năng trình bao bọc "ga" hoặc "debounce". Tôi nên lưu ý rằng ở một nơi khác quá! :)
yckart

49

Sử dụng jQuery tiết lưu / gỡ lỗi

jQuery debounce là một cách tốt cho những vấn đề như thế này. jsFidlle

$(window).scroll($.debounce( 250, true, function(){
    $('#scrollMsg').html('SCROLLING!');
}));
$(window).scroll($.debounce( 250, function(){
    $('#scrollMsg').html('DONE!');
}));

Tham số thứ hai là cờ "at_begin". Ở đây tôi đã chỉ ra cách thực thi mã cả ở "đầu cuộn" và "kết thúc cuộn".

Sử dụng Lodash

Theo gợi ý của Barry P, jsFiddle , underscore hoặc lodash cũng có một phần khuyết điểm, mỗi phần có apis hơi khác nhau.

$(window).scroll(_.debounce(function(){
    $('#scrollMsg').html('SCROLLING!');
}, 150, { 'leading': true, 'trailing': false }));

$(window).scroll(_.debounce(function(){
    $('#scrollMsg').html('STOPPED!');
}, 150));

Có thể sử dụng chức năng cuộn bình thường cùng lúc không? $ (cửa sổ) .scroll (function () {...});
Daniel Vogelnest

Tất nhiên, jQuery sẽ liên kết nhiều trình xử lý với một sự kiện mà bạn muốn.
Sinetheta

Cảm ơn cho việc cập nhật @BarryP Jsfiddle này cũng cung cấp lo-dash để bạn có thể tránh được những liên kết bên ngoài jsfiddle.net/qjggnyhf
Sinetheta

FYI, tôi đang gặp sự cố khi cuộn nhanh không hoàn nguyên. Có vẻ như bạn cần thêm một vài mili giây để gỡ lỗi "STOPPED", nếu không nó gây ra tình trạng đua trong đó, đôi khi, STOPPED kích hoạt trước khi BẮT ĐẦU và bạn kết thúc với mục bị kẹt như thể bạn vẫn đang cuộn. Tôi đã tạo lần lượt 150 và 160, và nó có vẻ thành công.
CodeChimp

Cảm ơn @CodeChimp, điều đó thật gọn gàng, nhưng tôi lo lắng về việc xử lý các trường hợp cạnh bằng cách sửa chúng 15 trong số 16 lần;) Có thể một trình xử lý duy nhất với tất cả logic bên trong sẽ an toàn nhất. Kiểm tra leadingtrailingchính bạn, sau đó chắc chắn rằng không thể có sự nhầm lẫn.
Sinetheta

9

Rob W đã kích hoạt Tôi kiểm tra một bài đăng khác ở đây về cơ bản là một bài đăng tương tự với bài đăng gốc của tôi. Đọc qua mà tôi tìm thấy một liên kết đến một trang web:

http://james.padolsey.com/javascript/special-scroll-events-for-jquery/

Điều này thực sự đã giúp giải quyết vấn đề của tôi rất tốt sau một chút điều chỉnh cho nhu cầu của riêng tôi, nhưng trên tất cả đã giúp giải quyết rất nhiều lỗi và tiết kiệm cho tôi khoảng 4 giờ tự tìm ra nó.

Thấy bài đăng này có vẻ có ích, tôi nghĩ tôi sẽ quay lại và cung cấp mã được tìm thấy ban đầu trên liên kết được đề cập, đề phòng trường hợp tác giả quyết định đi theo một hướng khác với trang web và cuối cùng gỡ liên kết xuống.

(function(){

    var special = jQuery.event.special,
        uid1 = 'D' + (+new Date()),
        uid2 = 'D' + (+new Date() + 1);

    special.scrollstart = {
        setup: function() {

            var timer,
                handler =  function(evt) {

                    var _self = this,
                        _args = arguments;

                    if (timer) {
                        clearTimeout(timer);
                    } else {
                        evt.type = 'scrollstart';
                        jQuery.event.handle.apply(_self, _args);
                    }

                    timer = setTimeout( function(){
                        timer = null;
                    }, special.scrollstop.latency);

                };

            jQuery(this).bind('scroll', handler).data(uid1, handler);

        },
        teardown: function(){
            jQuery(this).unbind( 'scroll', jQuery(this).data(uid1) );
        }
    };

    special.scrollstop = {
        latency: 300,
        setup: function() {

            var timer,
                    handler = function(evt) {

                    var _self = this,
                        _args = arguments;

                    if (timer) {
                        clearTimeout(timer);
                    }

                    timer = setTimeout( function(){

                        timer = null;
                        evt.type = 'scrollstop';
                        jQuery.event.handle.apply(_self, _args);

                    }, special.scrollstop.latency);

                };

            jQuery(this).bind('scroll', handler).data(uid2, handler);

        },
        teardown: function() {
            jQuery(this).unbind( 'scroll', jQuery(this).data(uid2) );
        }
    };

})();

5

Tôi đồng ý với một số nhận xét ở trên rằng việc lắng nghe trong thời gian chờ không đủ chính xác vì điều đó sẽ kích hoạt khi bạn ngừng di chuyển thanh cuộn đủ lâu thay vì khi bạn dừng cuộn. Tôi nghĩ một giải pháp tốt hơn là lắng nghe người dùng thả chuột (mouseup) ngay khi họ bắt đầu cuộn:

$(window).scroll(function(){
    $('#scrollMsg').html('SCROLLING!');
    var stopListener = $(window).mouseup(function(){ // listen to mouse up
        $('#scrollMsg').html('STOPPED SCROLLING!');
        stopListner(); // Stop listening to mouse up after heard for the first time 
    });
});

và một ví dụ về nó hoạt động có thể được nhìn thấy trong JSFiddle này


2
Điều này có vẻ tuyệt vời, nhưng nếu bạn đang cuộn bằng cử chỉ 2 ngón tay trên bàn di chuột hoặc con lăn, thì thao tác di chuột sẽ không được kích hoạt. Đây có lẽ là cách phổ biến nhất để cuộn, khiến nó có vấn đề.
Adam

1
Điểm tốt. Nhưng có khả năng có một vài bản sửa lỗi cho điều đó. Sử dụng sự kiện 'mousewheel' của jquery hoặc theo dõi nếu chuyển xuống trước và sử dụng cách tiếp cận thời gian chờ theo đề xuất của những người khác. Nhưng tôi nghĩ việc sử dụng kết hợp các câu trả lời khác cho các sự kiện trên con lăn chuột và câu trả lời này cho việc kéo thanh cuộn sẽ cho kết quả chính xác nhất
Theo

3

Bạn có thể đặt khoảng thời gian chạy cứ sau 500 ms hoặc lâu hơn, dọc theo các dòng sau:

var curOffset, oldOffset;
oldOffset = $(window).scrollTop();
var $el = $('.slides_layover'); // cache jquery ref
setInterval(function() {
  curOffset = $(window).scrollTop();
  if(curOffset != oldOffset) {
    // they're scrolling, remove your class here if it exists
    if($el.hasClass('showing_layover')) $el.removeClass('showing_layover');
  } else {
    // they've stopped, add the class if it doesn't exist
    if(!$el.hasClass('showing_layover')) $el.addClass('showing_layover');
  }
  oldOffset = curOffset;
}, 500);

Tôi chưa thử nghiệm mã này, nhưng nguyên tắc sẽ hoạt động.


2
function scrolled() {
    //do by scroll start
    $(this).off('scroll')[0].setTimeout(function(){
        //do by scroll end
        $(this).on('scroll',scrolled);
    }, 500)
}
$(window).on('scroll',scrolled);

Phiên bản rất nhỏ với khả năng bắt đầu và kết thúc


1

Ok, đây là một cái gì đó mà tôi đã sử dụng trước đây. Về cơ bản, bạn trông giữ một giới thiệu cuối cùng scrollTop(). Sau khi hết thời gian chờ, bạn kiểm tra dòng điện hiện tại scrollTop()và nếu chúng giống nhau, bạn đã hoàn tất việc cuộn.

$(window).scroll((e) ->
  clearTimeout(scrollTimer)
  $('header').addClass('hidden')

  scrollTimer = setTimeout((() ->
    if $(this).scrollTop() is currentScrollTop
      $('header').removeClass('hidden') 
  ), animationDuration)

  currentScrollTop = $(this).scrollTop()
)

1

Kiểu ES6 với kiểm tra đầu cuộn cũng bắt đầu.

function onScrollHandler(params: {
  onStart: () => void,
  onStop: () => void,
  timeout: number
}) {
  const {onStart, onStop, timeout = 200} = params
  let timer = null

  return (event) => {
    if (timer) {
      clearTimeout(timer)
    } else {
      onStart && onStart(event)
    }
    timer = setTimeout(() => {
      timer = null
      onStop && onStop(event)
    }, timeout)
  }
}

Sử dụng:

yourScrollableElement.addEventListener('scroll', onScrollHandler({
  onStart: (event) => {
    console.log('Scrolling has started')
  },
  onStop: (event) => {
    console.log('Scrolling has stopped')
  },
  timeout: 123 // Remove to use default value
}))


0

Đối với những ai vẫn cần thì đây là giải pháp

  $(function(){
      var t;
      document.addEventListener('scroll',function(e){
          clearTimeout(t);
          checkScroll();
      });
      
      function checkScroll(){
          t = setTimeout(function(){
             alert('Done Scrolling');
          },500); /* You can increase or reduse timer */
      }
  });


0

Điều này sẽ hoạt động:

var Timer;
$('.Scroll_Table_Div').on("scroll",function() 
{
    // do somethings

    clearTimeout(Timer);
    Timer = setTimeout(function()
    {
        console.log('scrolling is stop');
    },50);
});

0

Đây là cách bạn có thể xử lý điều này:

    var scrollStop = function (callback) {
        if (!callback || typeof callback !== 'function') return;
        var isScrolling;
        window.addEventListener('scroll', function (event) {
            window.clearTimeout(isScrolling);
            isScrolling = setTimeout(function() {
                callback();
            }, 66);
        }, false);
    };
    scrollStop(function () {
        console.log('Scrolling has stopped.');
    });
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>
</body>
</html>


0

Điều này sẽ phát hiện điểm dừng cuộn sau 1 mili giây (hoặc thay đổi nó) bằng cách sử dụng bộ hẹn giờ chung:

var scrollTimer;

$(window).on("scroll",function(){
    clearTimeout(scrollTimer);
    //Do  what you want whilst scrolling
    scrollTimer=setTimeout(function(){afterScroll()},1);
})

function afterScroll(){
    //I catched scroll stop.
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.