【问题标题】:JQuery Draggable with Touch Punch stops vertical scrollJQuery Draggable with Touch Punch 停止垂直滚动
【发布时间】:2016-11-25 07:11:11
【问题描述】:

我正在使用 JQuery Draggable 函数和 Touch Punch 来生成一个水平滑块列表,这些滑块可以通过单击和拖动来滚动。它在触摸和点击设备上效果很好。我面临的问题是,如果我尝试在触摸设备中向上或向下滚动,它不起作用。

我查看了 SO,发现从 TouchPunch 中删除“event.preventDefault”允许垂直滚动,这个修复的问题是,它只适用于某些设备,而不是全部。

我想知道是否有人有任何其他解决方案或替代方法来生成适用于触摸和点击事件的相同水平滑块。

这里是示例代码(JQuery Draggable):

$(function() {
  var slides = $('#list1 ul').children().length;
  var slideWidth = $('#list1').width();
  var min = 0;
  var max = -((slides - 1) * slideWidth);

  $("#list1 ul").width(slides * slideWidth).draggable({
    axis: 'x',
    drag: function(event, ui) {
      if (ui.position.left > min) ui.position.left = min;
      if (ui.position.left < max) ui.position.left = max;
    }
  });

    $("#list2 ul").width(slides * slideWidth).draggable({
    axis: 'x',
    drag: function(event, ui) {
      if (ui.position.left > min) ui.position.left = min;
      if (ui.position.left < max) ui.position.left = max;
    }
  });


});
#list1 {
  position: relative;
  height: 16em;
  width: 100%;
  text-align: middle;
  white-space: nowrap;
  overflow-x: hidden;
  overflow-y: hidden;
}

#list1 .floating-box {
  margin: auto;
  display: inline-block;
  width: 15em;
  height: 13.5em;
  margin: 0.1em;
  border: 0.2em solid black;
  background-color: white;
}

#list2 {
  position: relative;
  height: 16em;
  width: 100%;
  text-align: middle;
  white-space: nowrap;
  overflow-x: hidden;
  overflow-y: hidden;
}

#lis2 .floating-box {
  margin: auto;
  display: inline-block;
  width: 15em;
  height: 13.5em;
  margin: 0.1em;
  border: 0.2em solid black;
  background-color: white;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="list1">
    <ul>
    <p>One</p>
    <div class="floating-box">Floating box</div>
    <div class="floating-box">Floating box</div>
    <div class="floating-box">Floating box</div>
    </ul>
 </div>


  <div id="list2">
    <ul>
     <p>Two</p>
     <div class="floating-box">Floating box</div>
     <div class="floating-box">Floating box</div>
     <div class="floating-box">Floating box</div>
    </ul>
  </div>

如果我触摸 list1 或 list2 div 并尝试向上或向下滚动,它无法识别移动。任何帮助或指导将不胜感激。

【问题讨论】:

  • @kyunghwanjung 这就是我目前使用的,“可拖动”功能,问题是,我无法上下滚动。

标签: javascript jquery html css


【解决方案1】:

编辑
基于touchemovepageY属性判断滑动方向的思路。

我认为从长远来看,避免烦人的双击是个好主意(请参阅下面的第一个答案)
还是有妥协的余地,但要合理得多。

我尝试了很多东西......我得到的最好结果是当我放弃在touchmove上模拟滚动时。

下面是我现在使用三个触摸事件的方法:

  • touchstart 获取初始变量,例如:window scrollTop 和 pageY。

  • touchmove判断滑动方向并获取最后一页Y。

  • touchend 计算页面是否应该滚动到。
    为了可爱,我把结果值放在了.animate()
    我惊喜地发现它非常顺利地弥补了页面仅在 touchend 上滚动的事实。
    我认为很少有用户会注意到它;)。

由于“Touch-Punch”默认情况下适用于水平滑动,因此“妥协”仅影响垂直滚动。



这是代码:
live link 在支持触控的设备上试用。

$(function() {
    var slides = $('#list1 ul').children().length;
    var slideWidth = $('#list1').width();
    var min = 0;
    var max = -((slides - 1) * slideWidth);

    $(".draggable").width(slides * slideWidth).draggable({
        axis: 'x',
        drag: function(event, ui) {
            if (ui.position.left > min) ui.position.left = min;
            if (ui.position.left < max) ui.position.left = max;
        }
    });

    var startTouchX=0;
    var startTouchY=0;

    var actualPosX;
    var actualPosY;

    var eventCounter=0;
    var directionDetermined=false;
    var direction;

    var thisTouchX;
    var thisTouchY;

    var lastTouchY;

    $(document).on("touchstart", function(e) {
        // Actual document position
        actualPosX = $(document).scrollLeft();
        actualPosY = $(document).scrollTop();

        // StartTouches
        startTouchX = parseInt(e.originalEvent.touches[0].pageX);
        startTouchY = parseInt(e.originalEvent.touches[0].pageY);
    });

    $(document).on("touchmove", function(e) {

        // Arbitrary considering ONLY the fourth event... 
        // Touchmove fires way too many times!
        // We only need to determine the main direction ONCE.
        // This prevents an "s" swipe from messing this code.
        eventCounter++;
        if(eventCounter==4 && !directionDetermined){

            thisTouchX = parseInt(e.originalEvent.touches[0].pageX);
            thisTouchY = parseInt(e.originalEvent.touches[0].pageY);

            if ( (Math.abs(thisTouchX - startTouchX)) / Math.abs(thisTouchY - startTouchY) > 1){     //check swipe direction

                // HORIZONTAL
                $("#debug").html("HORIZONTAL");
                directionDetermined=true;

                // NO NEED here. This is re-enabled on touchend, if it has been disabled.
                //$(".draggable").draggable('enable');
            }
            else{

                // VERTICAL
                $("#debug").html("VERTICAL");
                directionDetermined=true;
                direction="vertical";

                $(".draggable").draggable('disable'); // Disable draggable.
            }
        }

        // Getting all the Y touches...
        // The "last" value will be used on touchend.
        lastTouchY = parseInt(e.originalEvent.touches[0].pageY);
        //$("#debug").html(lastTouchY);
    });

    $(document).on("touchend", function(e) {
            if(direction=="vertical"){
                //$("#debug").html(lastTouchY);

                var thisMoveY = -parseInt(lastTouchY - startTouchY);
                //$("#debug").html(thisMoveY);

                var newPosY = (actualPosY + thisMoveY);
                //$("#debug").html(actualPosX+ " " +newPosY);

                //window.scrollTo(actualPosX, newPosY);
                $("html,body").animate({ scrollTop: newPosY },400);
            }

            // Reset everything for a future swipe.
            startTouchX=0;
            startTouchY=0;
            eventCounter=0;
            directionDetermined=false;
            direction="";
            $("#debug").html("");

            // Re-enable draggable.
            $(".draggable").draggable('enable');
    });
});




第一个答案,使用“双击”来切换方向。

首先,Touch Punch 网站声明它基本上是一个 jQuery-UI hack 来处理 一些 实际未被 jQuery-UI 处理的情况... 并且可以找到Touch Punch失败的情况。

您的问题已报告给 Touch Punch 开发人员 here
作为对此的回答(用我的话来说),他们说这不是真正的错误或问题......
但是在使用相同触摸事件的两个不同“希望”操作上的用法“冲突”。
有时滚动页面,有时拖动元素。

作为解决方案提示,他们发布了this Fiddle
它建议找到一种在需要时禁用可拖动的方法。

但在此解决方案中,可滚动部分可拖动元素内。
这不是你的情况。
而且您几乎所有的移动屏幕空间都用于您的可拖动元素,因此没有足够的空间来触发它们周围的draggable("disable")

所以...我有这个想法,希望对您有所帮助。

如果您能找到一种优雅的方式来通知用户“双击”会改变移动方向。
在这里,我建议使用一个非常简单的“双箭头”来显示移动方向。
也许你会找到更好的东西。

这肯定是有点妥协的用户体验,要求他们双击...
但如果你的布局真的需要它,也许没问题。

所以在这里,我转载了你的initial issue
这里是the fix that I suggest

我只在三星 Galaxy S3 上尝试过,但应该可以在所有触控设备上使用。

$(function() {
    var slides = $('#list1 ul').children().length;
    var slideWidth = $('#list1').width();
    var min = 0;
    var max = -((slides - 1) * slideWidth);

    $(".draggable").width(slides * slideWidth).draggable({
        axis: 'x',
        drag: function(event, ui) {
            if (ui.position.left > min) ui.position.left = min;
            if (ui.position.left < max) ui.position.left = max;
        }
    });

    // Flag
    var draggableEnabled=true;

    // Find the doubletap position (to show a nice double arrow)
    var tapPosition=[];
    $(document).on("touchstart",function(e){
        tapPosition[0] = parseInt(e.touches[0].pageX) - $(document).scrollLeft() - ($("#arrows img").width()/2);
        tapPosition[1] = parseInt(e.touches[0].pageY) - $(document).scrollTop() - ($("#arrows img").width()/2);
    });

    Hammer(document).on("doubletap", function() {
        //alert("Double tap");
        draggableEnabled = !draggableEnabled;   // Toggle

        if(!draggableEnabled){
            $(".draggable").draggable('disable');   // Disables draggable (and touch Punch)
            $("#arrows img").css({
                    "transform":"rotate(90deg)",    // Nice vertical double arrow
                    "top":tapPosition[1],
                    left:tapPosition[0]
                }).fadeIn(600, function(){
                $(this).fadeOut(600);
            });

        }else{
            $(".draggable").draggable('enable');    // Enables draggable (and touch Punch)
            $("#arrows img").css({
                    "transform":"rotate(0deg)",     // Nice horizontal double arrow
                    "top":tapPosition[1],
                    left:tapPosition[0]
                }).fadeIn(600, function(){
                $(this).fadeOut(600);
            });
        }
    }); 
});

注意它使用Hammer.js (CDN) 来检测双击。

还有一些用于 double arrow 的额外 CSS。

#arrows img{
    width: 60vw;
    height: 60vw;
    position: fixed;
    top:calc( 50vh - 60vw );
    left:calc( 50vh - 60vw );
    z-index:1000;
    display:none;
}

【讨论】:

  • 在我看来这是个好主意,我在其他设备上测试过,效果很好。它会稍微影响用户体验,如果没有其他答案,我肯定会考虑这个。谢谢路易!
  • 能否请您检查我的答案,看看您是否可以完成?谢谢!
  • 我已经根据您确定方向的超级好主意做了一些事情。我会尽快编辑。
  • 做得好,它是最接近 SO 中的解决方案 :)
【解决方案2】:

这是我最接近的,我想知道是否有人可以改进这段代码:

$(watchlist).on("touchstart", function(e) {
        touchY = e.originalEvent.touches[0].pageY;
        touchX = e.originalEvent.touches[0].pageX;

    });

    $(watchlist).on("touchmove", function(e) {

        var fTouchY = e.originalEvent.touches[0].pageY;
        var fTouchX = e.originalEvent.touches[0].pageX;

        if ((Math.abs(fTouchX - touchX)) / Math.abs(fTouchY - touchY) > 1){ //check swipe direction

            $("#watchlist ul").draggable( 'enable'); //if swipe is horizontal
        }
        else{
            $("#watchlist ul").draggable( 'disable'); //if swipe is horizontal
        }


    });

此代码的问题在于,它仅在触摸移动完成后才停用可拖动功能,而不是在此期间。如果有人可以修改此代码,以便在满足条件时立即停用可拖动功能,在touchmove 期间,而不是之后,我会给他们赏金。

【讨论】:

    猜你喜欢
    • 2015-08-03
    • 1970-01-01
    • 2012-10-31
    • 1970-01-01
    • 2019-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多