在多个滚动事件上执行一次操作并阻止滚动

时间:2014-12-14 01:50:25

标签: javascript jquery angularjs scroll

我希望实现像Google Inbox landing page这样的滚动功能:

值得注意的是,无论您滚动滚轮的速度有多快或多少次,它都将计为"一个"然后进入下一步。这说起来容易做起来难,因为没有办法取消"滚动"事件。有一种方法可以取消DOMMouseScroll&但mousewheel事件却很棘手:

问题是取消这些事件的方式如下,使用return preventFn(ev)

   var preventFn = function (ev) {
      ev.returnValue = false;
      return false;
   };

Try it here

但这样做会导致scrollTop()动作中断。但没有它,滚动事件也会通过并将其混乱。

我可以通过使用超时的相当错误的实现做得更好(参见小提琴)。它工作正常,但如果用户在scrollTop()动画正在发生时滚动,那么主要的错误就是永久性的一切。

我如何纠正这一点,以及它像谷歌一样出色? (并且最好没有超时。在Google页面中,从第3步到第4步......我甚至无法察觉到任何超时,它似乎在我的鼠标滚轮开始移动时立即滚动。所以它似乎有可能)

3 个答案:

答案 0 :(得分:3)

似乎解决方案意味着使用锚点和超时。 灵感来自this post
我已经更新了你的plunkr。这是一个链接:http://plnkr.co/edit/GDdm7Z4OEzfh7ZwnQce7?p=preview

    app.directive('autoScroll', function($document, $timeout) {
    return {
        restrict: 'AE',
        link: function(scope, elem, attrs) {
            var delay = false;
            $document.on('mousewheel DOMMouseScroll', function(e) {
                e.preventDefault();
                if (delay) return;

                delay = true;
                $timeout(function() {
                    delay = false
                }, 100)

                var wd = e.originalEvent.wheelDelta || -e.originalEvent.detail;

                var a = angular.element('a');
                if (wd < 0) {
                    for (var i = 0; i < a.length; i++) {
                        var t = a[i].getClientRects()[0].top;
                        if (t >= 40) break;
                    }
                } else {
                    for (var i = a.length - 1; i >= 0; i--) {
                        var t = a[i].getClientRects()[0].top;
                        if (t < -20) break;
                    }
                }
                angular.element('html,body').animate({
                    scrollTop: a[i].offsetTop
                }, 500);
            });
        }
    }
});

答案 1 :(得分:0)

如果你想创建一个类似的网站,我建议你使用fullPage.js,如果你还没有尝试过。

关于超时问题,处理它并不是那么简单。 Mac OS X设备和Apple触控板或Magic Mouse具有相当大的惯性,滚动事件即使在停止滚动后1秒内也会被记录。

我会在Mac上试用Google网站,看看它是如何反应的,但同时我建议你仔细阅读我找到解决问题的方法: stopping mousewheel event from happening twice in OSX

答案 2 :(得分:0)

使用普通jquery: HTML:

   <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js">      </script>
<body>
 <main> 
    <div class="contslide">Liza1</div>
    <div class="contslide">Liza2</div>
    <div class="contslide">Liza3</div>
    <div class="contslide">Liza4</div>
    <div class="contslide">Liza5</div>
 </main>
 </body>

css:

  body{width:100%;height:100%;  overflow:hidden; margin:0px;}
  main{ position:absolute; width:100%;  height:100%;  font:20pt verdana;} 
  main div{width:100%;  height:100%; }
  main div:nth-child(odd) {background: #ff0000;}

jquery的:

  $(document).ready(function () {
  var delay = false;
  $(document).on('mousewheel DOMMouseScroll', function(event) {
    event.preventDefault();
    if(delay) return;

    delay = true;
    setTimeout(function(){delay = false},200)

    var wd = event.originalEvent.wheelDelta || -event.originalEvent.detail;

    var a= document.getElementsByClassName('contslide');
    if(wd < 0) {
      for(var i = 0 ; i < a.length ; i++) {
        var t = a[i].getClientRects()[0].top;
        if(t >= 40) break;
      }
    }
    else {
      for(var i = a.length-1 ; i >= 0 ; i--) {
        var t = a[i].getClientRects()[0].top;
        if(t < -20) break;
      }
    }
   $('html, body').animate({
    scrollTop: a[i].offsetTop
   });
   });
  });

以下是fiddle示例