【问题标题】:Detect Intentional Top and Bottom extra scroll检测有意的顶部和底部额外滚动
【发布时间】:2016-10-24 15:38:31
【问题描述】:

我正在尝试使用 javascript 检测有意的额外顶部/底部滚动。 $(window).scrollTop()window.pageYOffset 没有用,因为它们停在 Top 0,我想达到 top -X 之类的东西。对于底部,假设我的文档高度为 500,底部就像 bottom 5XX

编辑: 示例代码可以是:

$(window).scroll(function(){

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

});

GIF 示例:

【问题讨论】:

  • 我的第一个使用想法是检测/防止在移动设备上显示地址栏...是这样吗?无论如何,这可以通过在body first child周围设置一个内容包装器来实现......也许。问题:你尝试过什么吗?我在这里没有看到任何代码。
  • @LouysPatriceBessette 我想将它用于桌面,而不是手机。我添加了一些代码示例,但请注意$(window).scrollTop()window.pageYOffset 没有用处。
  • 这似乎是无限滚动的变体。

标签: javascript jquery


【解决方案1】:

我从您的问题中了解到的不仅仅是“检测过度滚动”...
但也可以使用它来创建一个动画,就像您在问题中展示的那样。

正如我 2 天前评论的那样,我使用包装器 div 提出了一个解决方案。

您可以在CodePen 或下面的 sn-p 中看到它。

$(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>

当页面在顶部或底部时检测滚动尝试...
用它来设置像你展示的动画是另一回事。

接近顶峰:
包装器的margin0em 动画到3em,将标题和内容向下推。
所以页面“看起来”像是被过度滚动了。

接近底部:
这是一个挑战...
不能用包装器的margin-bottom 对顶部做同样的事情,因为它可以工作……但在视口下方,这并不是我们真正想要的。

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

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

当拖动 滚动条、旋转 鼠标滚轮 并点击 键盘 上 4 个“常用”键中的一个(箭头和向上/向下翻页)。

我留下了很多 console.log(),您可以使用它们来探索它的工作原理并改进动画并使其成为您的口味。
;)

【讨论】:

  • 这是一个好方法。谢谢@Louys Patrice Bessette,但我想检测一个额外的滚动顶部/底部,而不是顶部/底部的第一个滚动,但是,你给了我一些线索来弄清楚如何找到我的答案。谢谢! :)
  • +50 因为你给了我一个活生生的例子,我找到了主要线索来找出我的解决方案。
  • 这是一个很有趣的不寻常问题。我很高兴你通过我的贡献找到了你需要的东西;)
【解决方案2】:

实际上存在一个名为 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;
}
&lt;div id="content"&gt;&lt;/div&gt;

【讨论】:

    【解决方案3】:

    感谢@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

    【讨论】:

    • 不客气,你有一个非常有趣的问题,但仍有一件事困扰着我,即使没有提供这样的功能,它也会检测到过度滚动,所以你应该考虑添加操作系统检查或提供动画如果平台不支持。
    • @KonstantinAzizov 就我的目的而言足以检测到触发回调的额外滚动意图,动画只是说明我在寻找什么的一种方式。
    猜你喜欢
    • 1970-01-01
    • 2017-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多