繁体   English   中英

使用JavaScript控制iOS Web应用程序中列表上的垂直滚动和水平滑动

[英]Controlling vertical scrolling and horizontal swiping on a list in an iOS web app with JavaScript

我正在创建一个专门针对手机的网络应用程序(主要是iPhone,但Android和WP即将推出......)。

其中一个屏幕包含滚动的项目列表。 我希望该列表的行为类似于内置的iOS Mail应用程序。

换一种说法...

  1. 如果用户触摸列表并向上或向下移动,则列表将垂直滚动。
  2. 如果用户向上或向下轻拂,则列表会以自然动量垂直滚动
  3. 如果用户触摸列表并向左移动 - 特定项目向左滑动,显示删除按钮。
  4. 重要 - 列表应该滚动项目应该滑动, 但不能同时滚动。

所以 - 弄清楚用户的意图是很重要的,这意味着我可能需要阻止任何响应,直到我弄清楚用户是在垂直还是水平移动她的手指。

只需在列表容器上设置这些CSS样式......

overflow-y: auto;
-webkit-overflow-scrolling: touch;

......我得到了#1和#2。 所以,我需要弄清楚如何实现#3。

我的第一个想法是实现这样的东西(伪代码)......

  1. 在列表容器上创建一个touchstart事件侦听器。 在回调中,存储用户的起始触摸位置的x坐标和y坐标。
  2. 在列表容器上创建一个touchmove事件侦听器。 在回调中,计算用户手指移动的距离(例如,delta_x和delta_y)
  3. 如果delta_x delta_y 都小于10像素 - 不要做任何事情(不要滚动列表或滑动项目) - 因为我们还没有弄清楚用户是计划向上/向下移动还是向左/向右移动。
  4. 如果EITHER delta_x OR delta_y 超过10个像素 - 我们可以假设用户移动得足够远以表达她的意图。 如果delta_y> delta_x,则假设她向上/向下移动,并允许列表滚动,但不要滑动项目。 如果delta_x> delta_y,假设她向左/向右移动,那么我们应该允许项目滑动,但不允许列表滚动。

我希望我在touchstarttouchmove使用event.preventDefault()来控制何时开始滚动。 例如,

div.addEventListener("touchstart", function(e) {
    touchStart = {
        x: e.touches[0].pageX,
        y: e.touches[0].pageY
    }
}, false);
div.addEventListener("touchmove", function(e) {
    touchNow = {
        x: e.touches[0].pageX,
        y: e.touches[0].pageY
    }
    var
        dx = touchStart.x - touchNow.x,
        dy = touchStart.y - touchNow.y;
    if ((Math.abs(dx) < 10) && (Math.abs(dy) < 10)) {
        // prevent scrolling
        e.preventDefault();
    } else if (Math.abs(dx) > Math.abs(dy) < 10) {
        // moving right/left - slide item
    } else {
        // moving up/down - allow scrolling
    }
}, false);

但是 - 这不起作用。 无论你移动多远,列表都不会滚动。

显然 - 我误解了触发滚动的内容,以及event.preventDefault()在此上下文中应该做什么。

那么 - 有没有办法完成我追求的目标?

我希望有一个纯粹的JavaScript解决方案(所以我更好地理解它),但jQuery方法可以。 我绝对希望尽可能避免使用jQuery插件/库/框架......

提前致谢!

我不建议重新发明轮子。 有许多库支持手势检测。 其中,我建议使用Hammer.js来检测触摸事件。

它没有任何依赖关系,它很小,只有3.96 kB缩小+ gzipped!

而这一切都与处理触摸事件无关。

在您的情况下,Hammer内置了swipe检测功能。

您可以通过指定以下内容来自定义默认滑动手势:

  • 方向:您想要检测滑动手势的方向( 更多信息
  • 阈值:识别前所需的最小距离
  • 速度:识别前所需的最小速度( 单位为每毫秒px

    和更多。

下面是一个简单的例子Stack Snippet似乎有一些模拟触摸事件的问题,小提琴工作正常 ):

 var myElement = document.getElementById("container"); var hammertime = new Hammer(myElement, {}); hammertime.get('swipe').set({ direction: 2 // 2 stands for left }) hammertime.on('swipe', function(event) { event.target.querySelector(".delete").classList.add("show"); }); 
 * { margin: 0; padding: 0; } #container { width: 250px; height: 300px; overflow-y: auto; -webkit-overflow-scrolling: touch; background: dodgerblue; } #list { height: 100%; list-style: none; } #list li { position: relative; box-sizing: border-box; width: 100%; height: 50px; border: 2px solid #fff; } #list li span.delete { display: inline-block; position: absolute; left: 250px; width: 50px; height: 40px; line-height: 40px; margin: 3px; text-align: center; background: #fff; transition: left 0.5s ease-in; } #list li span.delete.show { left: 170px; } 
 <script src="http://cdn.jsdelivr.net/hammerjs/2.0.4/hammer.min.js"></script> <div id="container"> <ul id="list"> <li class="item"><span class="delete">&#215;</span> </li> <li class="item"><span class="delete">&#215;</span> </li> <li class="item"><span class="delete">&#215;</span> </li> <li class="item"><span class="delete">&#215;</span> </li> <li class="item"><span class="delete">&#215;</span> </li> <li class="item"><span class="delete">&#215;</span> </li> <li class="item"><span class="delete">&#215;</span> </li> <li class="item"><span class="delete">&#215;</span> </li> <li class="item"><span class="delete">&#215;</span> </li> <li class="item"><span class="delete">&#215;</span> </li> </ul> </div> 


如果您对学习触摸事件的工作方式更感兴趣而不是完成工作,那么我建议您深入了解Hammer。


对于那些不能使用jQuery的人来说,还有一个小的Hammer.js jQuery插件

当我实现幻灯片时,我遇到了类似的问题。 这是对我有用的解决方案,希望它能帮到你:

function touchStart(event){
   if (!event) event = window.event;
   if(!touched){ 
      touched = true;
      var touchObj = event.changedTouches[0];
      touchXPos  = parseInt(touchObj.clientX);
      touchYPos  = parseInt(touchObj.clientY);
   }    
   return false;
}

当用户触摸屏幕时,cooridnate位置存储在touchXPos,touchYPos中,布尔变量“touching”设置为true。

function touchMove(event){
   if (!event) event = window.event;

   if(touched){
       var touchObj = event.changedTouches[0];
       var distanceX = touchXPos - parseInt(touchObj.clientX);
       var distanceY = touchYPos - parseInt(touchObj.clientY);


   if(!touchDirection) {
       if(Math.abs(distanceX) > Math.abs(distanceY)){
          if (distanceX > 0)  touchDirection = "right";
          else if (distanceX < 0) touchDirection = "left";
       }

       else{
          if (distanceY > 0) { touchDirection = "up"; }
          else if (distanceY < 0) {touchDirection = "down"; }
       }
   } 

   if (((touchDirection == "right") )|| ((touchDirection == "left"))){

       //update touchDirection
       if(Math.abs(distanceX) > Math.abs(distanceY)){
          if (distanceX > 0)  touchDirection = "right";
          else if (distanceX < 0) touchDirection = "left";
       }

       touchXPos = parseInt(touchObj.clientX);
       slideshow_mask.scrollLeft += distanceX;
   }

   else if (((touchDirection == "up") ) || ((touchDirection == "down") )){
       return false;
   }

   event.preventDefault();
   return false;
}

与您的方法类似,我会在触摸移动时确定delta-x和delta-y,我将其命名为distanceX和distanceY。 当这是第一次“移动”时,我确定了触摸方向,可以是右,左,上或下。 登记的下一个动作只能保持在这个初始的竖立状态,即上/下或左/右。 因此,如果初始方向例如是“右”,则用户只能水平滑动(向左或向右)但从不向上/向下滑动。

由于我的代码被设计为水平移动幻灯片,我只对水平移动感兴趣( - >在您可以看到的代码片段中,我更新了方向(左,右),存储了新的xPosition并移动了幻灯片这个方向),但它不应该太难以适应垂直滚动。

我有相同的任务,并编写了一个纯Javascript lib swiped.js,用于在列表上进行水平滑动

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM