2013-06-03 40 views
10

在移动Safari中,是否有可能允许一个绝对定位的div滚动而不允许整个页面在滚动到达边缘时弹起或滑动(弹性滚动)?防止整页滚动iOS

这里是我现在面临的问题的一小部分工作示例:

<!doctype html> 
<html> 
<head> 
    <meta charset="utf-8" /> 
    <meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"> 
    <meta name="apple-mobile-web-app-capable" content="yes" /> 
    <style> 
     * { 
      margin: 0; 
      padding: 0; 
      box-sizing: border-box; 
     } 
     #a, #b { 
      position: absolute; 
      top: 0; 
      left: 0; 
      height: 100%; 
      padding: 10px; 
      overflow: auto; 
     } 
     #a { 
      width: 80px; 
      background: #f00; 
     } 
     #b { 
      background: #00f; 
      left: 80px; 
      width: 100%; 
     } 
    </style> 
    <script src="http://code.jquery.com/jquery-1.10.1.min.js"></script> 
    <script> 
     function pdcb(e) { 
      e.preventDefault(); 
     } 
     function npcb(e) { 
      e.stopPropagation(); 
     } 
     $(document).on('touchstart touchmove', pdcb). 
        on('touchstart touchmove', '.scrollable', npcb); 
    </script> 
</head> 
<body> 
    <div id="a" class="scrollable"> 
     This<br> 
     should<br> 
     be<br> 
     scrollable<br> 
     but<br> 
     not<br> 
     scroll<br> 
     the<br> 
     whole<br> 
     page<br> 
     This<br> 
     should<br> 
     be<br> 
     scrollable<br> 
     but<br> 
     not<br> 
     scroll<br> 
     the<br> 
     whole<br> 
     page<br> 
     This<br> 
     should<br> 
     be<br> 
     scrollable<br> 
     but<br> 
     not<br> 
     scroll<br> 
     the<br> 
     whole<br> 
     page<br> 
     This<br> 
     should<br> 
     be<br> 
     scrollable<br> 
     but<br> 
     not<br> 
     scroll<br> 
     the<br> 
     whole<br> 
     page<br> 
     This<br> 
     should<br> 
     be<br> 
     scrollable<br> 
     but<br> 
     not<br> 
     scroll<br> 
     the<br> 
     whole<br> 
     page<br> 
    </div> 
    <div id="b"> 
     this should never scroll 
    </div> 
</body> 
</html> 

解决方案:

$(document).on('touchmove', function(e) { 
    e.preventDefault(); 
}).ready(function() { 
    $(".scrollable").on('touchstart', function(e) { 
     this.allowUp = (this.scrollTop > 0); 
     this.allowDown = (this.scrollTop < this.scrollHeight - this.clientHeight); 
     this.prevTop = null; 
     this.prevBot = null; 
     this.lastY = e.originalEvent.pageY; 
    }).on('touchmove', function(e) { 
     var event = e.originalEvent; 
     var up = (event.pageY > this.lastY), down = !up; 
     this.lastY = event.pageY; 

     if ((up && this.allowUp) || (down && this.allowDown)) 
      event.stopPropagation(); 
     else 
      event.preventDefault(); 
    }); 
}); 
+1

不,不是重复。有两个'div's改变的事情。 –

+2

人们标志着这是一个重复的 - 这不是一个重复的问题 - 只有引用的问题,以防止本地势头的iOS滚动完全交易 - 这个问题/解决方案是关于启用势头滚动具体的申报单,同时阻止滚动整个页面。用于具有许多固定位置元素的网络应用程序。 – 1nfiniti

+0

如果你想这与(在单页JS应用程序等)动态地添加元素的工作,更换'$( “滚动”)。在( 'touchstart',...)''为$(document.body的) .on('touchstart','.scrollable',...)'。 – micho

回答

11

当你不打你的div的边缘内容,您需要允许本地touchmove事件在该元素上工作(以便它可以滚动),但是您将要停止事件从冒泡DOM,以便它不会触发页面主体上的滚动。

当你碰到你的元素的边界时,你需要防止原生动量完全滚动

我为此使用的代码如下(对原作者致歉,这是从这个主题的教程改编的,我在过去发现了互联网的某处...似乎无法找到URL现在虽然):

其中ELEM是您的DOM节点

elem.addEventListener('touchstart', function(event){ 
    this.allowUp = (this.scrollTop > 0); 
    this.allowDown = (this.scrollTop < this.scrollHeight - this.clientHeight); 
    this.prevTop = null; this.prevBot = null; 
    this.lastY = event.pageY; 
}); 

elem.addEventListener('touchmove', function(event){ 
    var up = (event.pageY > this.lastY), down = !up; 
    this.lastY = event.pageY; 

    if ((up && this.allowUp) || (down && this.allowDown)) event.stopPropagation(); 
    else event.preventDefault(); 
}); 

我通常通过它们限定元件的阵列和环 - 应用此代码到每一个迭代。

祝你好运,希望这会有所帮助。

+0

我还假设你的.scrollable类使用'-webkit-overflow-scrolling:touch'?如果不是的话,它应该:) – 1nfiniti

+1

对于那些被格式困惑的人:原来的海报添加了一个“解决方案”部分,它接受了这个代码并实现了它。这对我来说很有用。 – micho

+0

如果您正在使用这个动态应用程序,请记住在更换事件侦听器时将它们重新绑定到新元素上!我取代'elem.addEventListener'为jQuery的'$(document.body的)。在( “touchstart”, “.scrollable”,函数(){...});' – micho

18

最初的答案是太棒了,但有一些缺陷,我决定:

  • 如果一个元素是在顶部或底部,它不会滚动,并分别向下。
  • 如果动态添加元素,则不会有滚动处理程序。
  • 有未使用的变量(prevTop,prevBot)

我的回答解决了这些。 (请注意,我用.scroll-y,而不是.scrollable

首先,添加这些CSS规则:

.scroll-y { 
    overflow-y: auto; 
    overflow-x: hidden; 
    -webkit-overflow-scrolling: touch; /* nice webkit native scroll */ 
} 

.scroll-y类添加到你想滚动的任何元素。

然后,添加这个JS的地方:

// Disable scroll for the document, we'll handle it ourselves 
$(document).on('touchmove', function(e) { 
    e.preventDefault(); 
}); 

// Check if we should allow scrolling up or down 
$(document.body).on("touchstart", ".scroll-y", function (e) { 
    // If the element is scrollable (content overflows), then... 
    if (this.scrollHeight !== this.clientHeight) { 
    // If we're at the top, scroll down one pixel to allow scrolling up 
    if (this.scrollTop === 0) { 
     this.scrollTop = 1; 
    } 
    // If we're at the bottom, scroll up one pixel to allow scrolling down 
    if (this.scrollTop === this.scrollHeight - this.clientHeight) { 
     this.scrollTop = this.scrollHeight - this.clientHeight - 1; 
    } 
    } 
    // Check if we can scroll 
    this.allowUp = this.scrollTop > 0; 
    this.allowDown = this.scrollTop < (this.scrollHeight - this.clientHeight); 
    this.lastY = e.originalEvent.pageY; 
}); 

$(document.body).on('touchmove', ".scroll-y", function(e) { 
    var event = e.originalEvent; 
    var up = event.pageY > this.lastY; 
    var down = !up; 
    this.lastY = event.pageY; 

    if ((up && this.allowUp) || (down && this.allowDown)) { 
    event.stopPropagation(); 
    } else { 
    event.preventDefault(); 
    } 
}); 
+0

这是为我工作的,谢谢@ micho! – matthewpavkov

+1

我希望我可以将这个数字提高一百万倍,我一直在寻找一个可行的解决方案,所以谢谢! –

0

我相信bouncefix.js是这个问题的一个简易的解决方案。

0

Aaron Gray提供的说明帮助!

见链接: http://blog.christoffer.me/six-things-i-learnt-about-ios-safaris-rubber-band-scrolling/

<!doctype html> 
<html lang="en"> 
<head> 
    <meta charset="utf-8"> 
    <meta name="viewport" content="minimum-scale=1.0, width=device-width, maximum-scale=1.0, user-scalable=no, initial-scale=1"> 
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 
    <style> 

     .page{ 
      font-size: 24px; 
      overflow: scroll; 
     } 

     .menu{ 
      position: fixed; 
      top: 0; 
      bottom: 0; 
      left: 0; 
      width: 80%; 
      background: gray; 
      z-index: 1; 
      font-size: 10px; 
      overflow: scroll; 
      /* uncomment to get smooth momentum scroll, but also a rubber band effect */ 
      /*-webkit-overflow-scrolling: touch;*/ 
     } 

     .menu-item{ 
      padding: 10px; 
      background: darkgray; 
      font-size: 24px; 
     } 

    </style> 
</head> 

<body> 

<div class="menu scrollable"> 
    <div class="menu-item">hello world</div> 
    <div class="menu-item">hello world</div> 
    <div class="menu-item">hello world</div> 
    <div class="menu-item">hello world</div> 
    <div class="menu-item">hello world</div> 
    <div class="menu-item">hello world</div> 
    <div class="menu-item">hello world</div> 
    <div class="menu-item">hello world</div> 
    <div class="menu-item">hello world</div> 
    <div class="menu-item">hello world</div> 
    <div class="menu-item">hello world</div> 
    <div class="menu-item">hello world</div> 
    <div class="menu-item">hello world</div> 
    <div class="menu-item">hello world</div> 
    <div class="menu-item">hello world</div> 
    <div class="menu-item">hello world</div> 
    <div class="menu-item">hello world</div> 
    <div class="menu-item">hello world</div> 
</div> 

<div class="page disable-scrolling"> 
    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's 
    standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make 
    a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, 
    remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing 
    Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions 
    of Lorem Ipsum. 
</div> 

<script> 


    document.ontouchmove = function (event) { 

     var isTouchMoveAllowed = true, target = event.target; 

     while (target !== null) { 
      if (target.classList && target.classList.contains('disable-scrolling')) { 
       isTouchMoveAllowed = false; 
       break; 
      } 
      target = target.parentNode; 
     } 

     if (!isTouchMoveAllowed) { 
      event.preventDefault(); 
     } 

    }; 

    function removeIOSRubberEffect(element) { 

     element.addEventListener("touchstart", function() { 

      var top = element.scrollTop, totalScroll = element.scrollHeight, currentScroll = top + element.offsetHeight; 

      if (top === 0) { 
       element.scrollTop = 1; 
      } else if (currentScroll === totalScroll) { 
       element.scrollTop = top - 1; 
      } 

     }); 

    } 

    removeIOSRubberEffect(document.querySelector(".scrollable")); 


</script> 

</body> 
</html>