【问题标题】:How to implement swipe gestures for mobile devices?如何为移动设备实现滑动手势?
【发布时间】:2013-02-11 15:24:10
【问题描述】:

我有一个用 AngularJS 制作的应用程序,它有箭头键导航来切换视图。

我想在触摸设备上使用滑动来实现这种导航。我尝试了jGestures 库,但滑动效果不佳。 建议我不要使用jquery mobile

有没有其他方式来实现滑动?

编辑: 它不会干净地检测滑动。我在包括 iPad 在内的多种设备上对其进行了测试,它需要多次滑动才能执行操作(在我的情况下是路由)。

【问题讨论】:

  • 您可能想详细说明您在使用 jGestures 时遇到的问题。我自己没有使用过它,但它看起来像是我为简单的手势支持而编写的自定义代码的强大版本(在其他地方也可以看到)。
  • "我被建议不要使用 jquery mobile。"为什么?

标签: javascript mobile touch swipe gestures


【解决方案1】:

我根据自己的需要制作了这个功能。

请随意使用。在移动设备上运行良好。

function detectswipe(el,func) {
  swipe_det = new Object();
  swipe_det.sX = 0; swipe_det.sY = 0; swipe_det.eX = 0; swipe_det.eY = 0;
  var min_x = 30;  //min x swipe for horizontal swipe
  var max_x = 30;  //max x difference for vertical swipe
  var min_y = 50;  //min y swipe for vertical swipe
  var max_y = 60;  //max y difference for horizontal swipe
  var direc = "";
  ele = document.getElementById(el);
  ele.addEventListener('touchstart',function(e){
    var t = e.touches[0];
    swipe_det.sX = t.screenX; 
    swipe_det.sY = t.screenY;
  },false);
  ele.addEventListener('touchmove',function(e){
    e.preventDefault();
    var t = e.touches[0];
    swipe_det.eX = t.screenX; 
    swipe_det.eY = t.screenY;    
  },false);
  ele.addEventListener('touchend',function(e){
    //horizontal detection
    if ((((swipe_det.eX - min_x > swipe_det.sX) || (swipe_det.eX + min_x < swipe_det.sX)) && ((swipe_det.eY < swipe_det.sY + max_y) && (swipe_det.sY > swipe_det.eY - max_y) && (swipe_det.eX > 0)))) {
      if(swipe_det.eX > swipe_det.sX) direc = "r";
      else direc = "l";
    }
    //vertical detection
    else if ((((swipe_det.eY - min_y > swipe_det.sY) || (swipe_det.eY + min_y < swipe_det.sY)) && ((swipe_det.eX < swipe_det.sX + max_x) && (swipe_det.sX > swipe_det.eX - max_x) && (swipe_det.eY > 0)))) {
      if(swipe_det.eY > swipe_det.sY) direc = "d";
      else direc = "u";
    }

    if (direc != "") {
      if(typeof func == 'function') func(el,direc);
    }
    direc = "";
    swipe_det.sX = 0; swipe_det.sY = 0; swipe_det.eX = 0; swipe_det.eY = 0;
  },false);  
}

function myfunction(el,d) {
  alert("you swiped on element with id '"+el+"' to "+d+" direction");
}

要使用该功能,只需像这样使用它

detectswipe('an_element_id',myfunction);

detectswipe('an_other_element_id',my_other_function);

如果检测到滑动,则使用参数 element-id 和“l,r,u,d”(左、右、上、下)调用函数“myfunction”。

示例:http://jsfiddle.net/rvuayqeo/1/


我(UlysseBN)基于这个使用更现代的 JavaScript 制作了 a new version of this script,看起来它在某些情况下表现更好。如果您认为应该编辑此答案,请告诉我,如果您是原作者并且最终进行了编辑,我将删除我的答案。

【讨论】:

  • 谢谢。我建议动态设置min_xmin_x = Math.abs(swipe_det.eY - swipe_det.sY)。其他方向的模拟。因为当您向上滑动 400 像素并且仅向右滑动 40 像素时,您可能打算向上滑动。但是,您的代码会识别出向右滑动。
  • @EscapeNetscape 我喜欢你的滑动检测解决方案。但它错误地将单击和双击识别为滑动。我将如何解决这个问题?
  • 我对脚本、javascript 1.8 和一些逻辑进行了一些更新。例如,如果你使用 deltas,你实际上并不需要 min_x、max_x、min_y 和 max_y。此外,通过比较增量 (abs((eX - sX) / (eY - sY)) 在垂直和水平之间进行选择会更精确。你可以看到我的叉子here。如果此评论获得足够多的支持(比如 5),我将编辑答案。
  • 我仍然无法相信原生 jQuery 没有适当的滑动事件处理。感谢您有思想的灵魂发布此代码!
  • @UlysseBN 你能用正确的代码编辑和更新答案吗? escapeNetscape 我使用了您的代码,但是当我向左或向右滑动时,我在 JS 控制台谷歌浏览器中收到此错误,滑动有效,但如何摆脱此错误?干预] 由于目标被视为被动chromestatus.com/features/5093566007214080,因此无法阻止被动事件侦听器内部的默认值
【解决方案2】:

你试过 Hammerjs 吗?它通过使用触摸的速度支持滑动手势。 http://eightmedia.github.com/hammer.js/

【讨论】:

  • 我使用了quojs.tapquo.com。它运作良好。听说过很多关于 HammerJS 的正面评价,会在其他项目中尝试。感谢您的回复。
  • 我写了一个简单的服务包装 Hammerjs。与 Angular 配合得很好。
  • 感谢推荐! hammerjs 可以与当前版本的 JQuery 一起使用,而无需迁移 jquery.mobile。没有警告,没有错误。不错!
【解决方案3】:

还有一个名为 angular-gestures 的 AngularJS 模块,它基于hammer.js: https://github.com/wzr1337/angular-gestures

【讨论】:

    【解决方案4】:

    我知道无耻的插件,但你可能想考虑我写的一个 jQuery 插件:

    https://github.com/benmajor/jQuery-Mobile-Events

    它不需要 jQuery Mobile,只需要 jQuery。

    【讨论】:

    • 目前为止不错的插件,因为我在使用 jquery mobile 时遇到了问题!
    【解决方案5】:

    注意: 受到EscapeNetscape's answer 的极大启发,我在评论中使用现代javascript 编辑了他的脚本。由于用户的兴趣和 4 小时的 jsfiddle.net 停机时间,我对此做出了回答。我选择不编辑原始答案,因为它会改变一切......


    这是一个detectSwipe 函数,运行良好(在我的一个网站上使用)。我建议你在使用它之前阅读它。随意查看/编辑答案。

    // usage example
    detectSwipe('swipeme', (el, dir) => alert(`you swiped on element with id ${el.id} to ${dir} direction`))
    
    // source code
    
    // Tune deltaMin according to your needs. Near 0 it will almost
    // always trigger, with a big value it can never trigger.
    function detectSwipe(id, func, deltaMin = 90) {
      const swipe_det = {
        sX: 0,
        sY: 0,
        eX: 0,
        eY: 0
      }
      // Directions enumeration
      const directions = Object.freeze({
        UP: 'up',
        DOWN: 'down',
        RIGHT: 'right',
        LEFT: 'left'
      })
      let direction = null
      const el = document.getElementById(id)
      el.addEventListener('touchstart', function(e) {
        const t = e.touches[0]
        swipe_det.sX = t.screenX
        swipe_det.sY = t.screenY
      }, false)
      el.addEventListener('touchmove', function(e) {
        // Prevent default will stop user from scrolling, use with care
        // e.preventDefault();
        const t = e.touches[0]
        swipe_det.eX = t.screenX
        swipe_det.eY = t.screenY
      }, false)
      el.addEventListener('touchend', function(e) {
        const deltaX = swipe_det.eX - swipe_det.sX
        const deltaY = swipe_det.eY - swipe_det.sY
        // Min swipe distance, you could use absolute value rather
        // than square. It just felt better for personnal use
        if (deltaX ** 2 + deltaY ** 2 < deltaMin ** 2) return
        // horizontal
        if (deltaY === 0 || Math.abs(deltaX / deltaY) > 1)
          direction = deltaX > 0 ? directions.RIGHT : directions.LEFT
        else // vertical
          direction = deltaY > 0 ? directions.UP : directions.DOWN
    
        if (direction && typeof func === 'function') func(el, direction)
    
        direction = null
      }, false)
    }
    #swipeme {
      width: 100%;
      height: 100%;
      background-color: orange;
      color: black;
      text-align: center;
      padding-top: 20%;
      padding-bottom: 20%;
    }
    <div id='swipeme'>
      swipe me
    </div>

    【讨论】:

    • 我看过你的代码,但我没有发现这与原始答案有太大区别。你能解释一下你做了什么改变吗?我的应用程序被人们在新旧浏览器上使用,所以我认为你的答案中的现代 JS 不适用于所有浏览器。顺便说一句,当我确实评论了 e.preventDefault();在最初的答案中,错误似乎已经消失了,我需要这条线,还是我可以留下评论?请确认我。我添加滑动的 div 不需要水平滚动,所以我认为如果我评论那行应该没问题,请确认我。
    • 是否可以检测到我们可以向上滑动但不能再向上移动屏幕,即我们已经到了顶部?我正在尝试解决一个问题,即我无法检测到页面上的滚动,但由于您的逻辑可以检测到滑动,但我需要确定是否在滑动时不能再向上移动,即容器元素的顶部在查看。
    【解决方案6】:

    锤击时间!

    我使用过 Hammer JS,它可以与手势配合使用。从这里阅读详细信息:https://hammerjs.github.io/

    好在它比 jQuery mobile 更轻、更快速。您也可以在他们的网站上进行测试。

    【讨论】:

    • 这不是和 4 年前 2013 年发布的 answer above 插入同一个库吗?
    【解决方案7】:

    我喜欢您的解决方案并在我的网站上实施了它 - 但是,有一些小的改进。只是想分享我的代码:

    function detectSwipe(id, f) {
        var detect = {
            startX: 0,
            startY: 0,
            endX: 0,
            endY: 0,
            minX: 30,   // min X swipe for horizontal swipe
            maxX: 30,   // max X difference for vertical swipe
            minY: 50,   // min Y swipe for vertial swipe
            maxY: 60    // max Y difference for horizontal swipe
        },
            direction = null,
            element = document.getElementById(id);
    
        element.addEventListener('touchstart', function (event) {
            var touch = event.touches[0];
            detect.startX = touch.screenX;
            detect.startY = touch.screenY;
        });
    
        element.addEventListener('touchmove', function (event) {
            event.preventDefault();
            var touch = event.touches[0];
            detect.endX = touch.screenX;
            detect.endY = touch.screenY;
        });
    
        element.addEventListener('touchend', function (event) {
            if (
                // Horizontal move.
                (Math.abs(detect.endX - detect.startX) > detect.minX)
                    && (Math.abs(detect.endY - detect.startY) < detect.maxY)
            ) {
                direction = (detect.endX > detect.startX) ? 'right' : 'left';
            } else if (
                // Vertical move.
                (Math.abs(detect.endY - detect.startY) > detect.minY)
                    && (Math.abs(detect.endX - detect.startX) < detect.maxX)
            ) {
                direction = (detect.endY > detect.startY) ? 'down' : 'up';
            }
    
            if ((direction !== null) && (typeof f === 'function')) {
                f(element, direction);
            }
        });
    }
    

    像这样使用它:

    detectSwipe('an_element_id', myfunction);
    

    或者

    detectSwipe('another_element_id', my_other_function);
    

    如果检测到滑动,则使用参数 element-id 和 'left''right''up''down' 调用函数 myfunction

    【讨论】:

    • 好发现!谢谢,改变了条件。
    【解决方案8】:

    我查看了几种解决方案,但都失败了,滚动和选择文本是最大的困惑。我没有向右滚动,而是关闭了框等。

    我刚刚完成了为我完成所有工作的实现。

    https://github.com/webdevelopers-eu/jquery-dna-gestures

    它是 MIT,所以随心所欲 - 是的,它真的很简单 - 缩小了 800 字节。您可以在我的(开发中的)网站https://cyrex.tech 上查看它 - 在触摸设备上向右滑动应该会关闭弹出窗口。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多