检测故意的顶部和底部额外滚动

时间:2016-10-19 14:46:24

标签: javascript jquery

我试图用javascript检测有意的额外顶部/底部滚动。 $(window).scrollTop()window.pageYOffset没有用,因为它们停在前0 ,我希望达到类似 top -X 的效果。对于底部,假设我的文档高度为500,则底部将类似于底部5XX

修改 示例代码可以是:

$(window).scroll(function(){

  if(intentionalScrollTop){
    // Do something
  }else if(intentionalScrollDown){
    // Do something
  }

});

Gif示例: enter image description here

3 个答案:

答案 0 :(得分:2)

我从你的问题中理解的不仅是“检测到过度滚动”...... 但也可以用它来创建你在问题中显示的动画。

我使用包装器div制作了解决方案,正如我在2天前评论过的那样。

您可以在CodePen或下面的代码段中看到它。

$(document).ready(function(){
	    
    var at_Top=true;
    var at_Bottom=false;
	var previous_scrolled;
	var triggerTime=0;
    var scroll_dir=false;   // false=>Down true=>up
	var scrolled_bottom = $("body").height() - $(window).height();
	var animationDelay = 300;
	var animationTimeout = 350;		//Max delay between 2 triggers is 1 sec.
									//So keep this value under 400ms
									//Because one complete animation is 300ms+350ms+300ms.
									//To have longer animation delays, add time to the triggerDelay
	
	var triggerDelay=0;	// You can add more delay to allow the next trigger (in seconds).
	
    $(window).scroll(function(){
        var scrolled=$(window).scrollTop();

        // Reached the top?
        if(scrolled==0){
            at_Top=true;
        }else{
            at_Top=false;
        }

        // Reached the bottom?
        if(scrolled==scrolled_bottom){
            at_Bottom=true;
        }else{
            at_Bottom=false;
        }
        
        // Scroll direction
		if( $(this).scrollTop() > previous_scrolled ){
			scroll_dir=false;  //scroll down
		}else{
			scroll_dir=true;  //scroll up
		}
		
		// Keep previous scrollTop position in memory
		previous_scrolled = $(this).scrollTop();
		
		animationTrigger();
    });

	function animationTrigger(){
        if(at_Top && scroll_dir){
            console.log("Scrolling when at top.");
			$("#wrapper").stop().animate({"margin-top":"3em"},animationDelay);
			setTimeout(function(){
				$("#wrapper").stop().animate({"margin-top":0},animationDelay);
			},animationTimeout);
			clearTimeout(clearConsole);
			var clearConsole = setTimeout(function(){
				console.clear();
			},3000);
        }
        if(at_Bottom && !scroll_dir){
            console.log("Scrolling when at bottom.")
			$("#header").stop().animate({"height":0},animationDelay);
			$("#footer-spacer").stop().animate({"height":"3em"},animationDelay);
			setTimeout(function(){
				$("#header").stop().animate({"height":"3em"},animationDelay);
				$("#footer-spacer").stop().animate({"height":0},animationDelay);
			},animationTimeout);
			clearTimeout(clearConsole);
			var clearConsole = setTimeout(function(){
				console.clear();
			},3000);
        }
    }
	
    // KEYBOARD ARROWS UP/DOWN AND PAGE UP/DOWN SCROLLING
    $(window).on("keydown",function(e){
        //console.log(e.which);
        if( (e.which==38) || (e.which==33) ){    // Arrow up or Page up
            scroll_dir=true;
        }
        if( (e.which==40) || (e.which==34) ){    // Arrow down or Page down
            scroll_dir=false;
        }
		
		// Limit triggers to 1 per second... Because when holding a key down for long, it triggers too fast...
		var thisSecond = new Date().getSeconds()
        if( (triggerTime != thisSecond) || (triggerTime < (thisSecond - triggerDelay) ) ){
            animationTrigger();
            triggerTime=thisSecond;
        }
    })

    // WHEEL SCROLLING
    // Inspired from this SO answer: http://stackoverflow.com/a/7309786/2159528

    //Firefox
    $(window).bind('DOMMouseScroll', function(e){
        var scrolled2=$(window).scrollTop();
        
        if(e.originalEvent.detail > 0) {
            scroll_dir=false;  //scroll down
            //console.log("down");
        }else {
            scroll_dir=true;   //scroll up
            //console.log("up");
        }
        
		// Limit triggers to 1 per second... Because wheel turns quite fast.
        var thisSecond = new Date().getSeconds()
        if( (triggerTime != thisSecond) || (triggerTime < (thisSecond - triggerDelay) ) ){
            animationTrigger();
            triggerTime=thisSecond;
        }
    });

    //IE, Opera, Safari
    $(window).bind('mousewheel', function(e){
		
        if(e.originalEvent.wheelDelta < 0) {
            scroll_dir=false;  //scroll down
        }else {
            scroll_dir=true;   //scroll up
        }
        
        // Limit triggers to 1 per second... Because wheel turns quite fast.
        var thisSecond = new Date().getSeconds()
        if( (triggerTime != thisSecond) || (triggerTime < (thisSecond - triggerDelay) ) ){
            animationTrigger();
            triggerTime=thisSecond;
        }
    });

});	// End Document.ready
body,wrapper{
    padding:0;
    margin:0;
    height:100;
}
#page{
    height:1500px;
    width:100%;
}
#header,#footer{
    height:3em;
    padding:0.5em;
    background-color:cyan;
}
#content{
    height:calc(100% - 8em);    /* -8em for header and footer... (height: 3em + padding: 2x 0,5em) */
    padding:0 0.5em;
    overflow:hidden;
}
#footer-spacer{
    height:0px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="wrapper">
    <div id="page">
        <div id="header">
            This is the page's top
        </div>
        <div id="content">
            <h1>Scroll this page to see the overscroll effect at top and bottom</h1>
            <br>
            <ul>
                <li>using the mouse wheel</li>
                <li>keyboard arrows</li>
                <li>keyboard page up/down</li>
            </ul>
            <br>
            <br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
            Content...<br>
        </div>
        
        <div id="footer">
            This is the page's bottom
        </div>
        <div id="footer-spacer"></div>
    </div>
</div>

当页面位于顶部或底部时,检测滚动尝试... 用它来设置你展示的动画是另一个。

接近顶端:
包装器的margin动画从0em3em,将标题和内容向下推。
所以页面“看起来”就像过度滚动。

底部的方法:
这是一个挑战...
使用包装器的margin-bottom不能与顶部相同,因为它可以工作......但是在视口下面,这不是我们想要的。

所以在这种情况下,我将“内容”定义为height:calc(100% - 8em) (页眉和页脚都有height:3empadding:0.5em只是为了确保包装纸100%填充。动画的空div是页脚下...当它的高度从0em传递到3em时,它会通过向上推动页脚来创建过度滚动“幻觉”。 / p>

请注意,标题会在同一时间缩回,以便释放空间。此时,标题不可见,为什么不呢?

此示例适用于拖动滚动条,旋转鼠标滚轮并点击键盘上的4个“常用”键中的1个(箭头和页面向上/向下)。

我留下了很多console.log(),你可以用它来探索它是如何工作的,并改进动画并使它成为你的品味。
;)

答案 1 :(得分:0)

实际上存在一个名为overscroll的库,但不幸的是,这仅适用于Safari,因为Chrome已取消对过度滚动号码的支持。

所以我这样做的唯一方法是监听鼠标滚轮事件,检查当前滚动位置是在页面顶部还是在页面底部,然后滚动目标是否匹配滚动区域返回true

请记住,即使系统不支持滚动,也会触发事件。因此,如果您希望仅在滚动发生时才使其正常工作,请确保检查用户的操作系统是否为macOS(navigator.platform === 'MacIntel')。

document.getElementById("content").innerHTML = new Array(60).fill(0).map(function() {
    return '<div>Sample text</div>';
   }).join('');

document.onwheel = function (event) {
  if(intentionalScrollTop(event)) {
    console.log('overscrolled top');
  } else if(intentionalScrollBottom(event)) {
    console.log('overscrolled bottom');
  }
}
  
function intentionalScrollTop (event) {
  return document.body.scrollTop === 0 && event.deltaY < 0;
}
  
function intentionalScrollBottom (event) {
  return (window.innerHeight + window.scrollY) >= document.body.offsetHeight && event.deltaY > 0;
}
<div id="content"></div>

答案 2 :(得分:0)

感谢@Louys和@Konstantin,我找到了一些线索来得到答案。

要使用跨浏览器支持检测滚动事件,我使用了this reference,这会创建一个事件监听器addWheelListener( elem, callback, useCapture )

然后使用scrollPos我可以检测滚动是在顶部/底部边缘还是没有,使用e.deltaYmaxScrollTopmaxScrollBottom我可以触发额外滚动消息

$(document).ready(function(){

  var canvasHeight    = ($("body").height() - $(window).height()).toFixed(0),
      elem            = document.getElementsByTagName("BODY")[0],
      maxScrollTop    = -200,
      maxScrollBottom = 200,
      scrollTop       = false,
      scrollBottom    = false;

  addWheelListener( elem, function( e ) {  

    var scrollPos = $(window).scrollTop();

    // Is Scroll at Top or Bottom edge?
    if(scrollPos === 0 || scrollPos === parseInt(canvasHeight)){
      if(e.deltaY < -1){
        if(e.deltaY < maxScrollTop){
          $('#message').text('Extra Scroll Top');
          console.log('Extra Scroll Top');
        }

        // This can be removed if you dont need to detect the first scroll top.
        if(!scrollTop){
          scrollTop = true;
          $('#message').text('Scroll Top');
          console.log('Scroll Top');
        }
      }else if(e.deltaY > 1){
        if(e.deltaY > maxScrollBottom){
          $('#message').text('Extra Scroll Bottom');
          console.log('Extra Scroll Bottom');
        }

        // This can be removed if you dont need to detect the first scroll bottom.
        if(!scrollBottom){
          scrollBottom = true;
          $('#message').text('Scroll Bottom');
          console.log('Scroll Bottom');
        }
      }
    }else{
      // Clean Scroll positions.
      scrollTop     = false;
      scrollBottom  = false;
      $('#message').text('Not at the top/bottom edge');
      console.log('Not at the top/bottom edge');
    }

  }, {passive: true});


}); // End Document.ready

以下是使用CodePen的工作示例。

http://codepen.io/xWaZzo/pen/NRorKj