水平拖动阻碍了页面默认的垂直滚动

问题描述 投票:0回答:2

我已经创建了一个 codepen 我想要实现的目标。

我正在使用几个水平可拖动项目创建时间线概述。除了

jquery
jquery-ui
之外,我还使用
jquery-ui-touch-punch
来实现移动设备上的所有手势。在桌面上一切正常,但在移动设备上却不行。

不幸的是,

$(".timeLineItemContainer").draggable({ ... });
极具侵略性,它还吞噬了我的垂直滚动行为,导致当我触摸其中一个项目时,我无法在移动设备上向下滚动

不知何故,我需要根据滚动操作的方向启用或禁用项目的拖动功能。当我禁用

event.preventDefault();

 中的 
jquery-ui-touch-punch.js
 时,它会向下滚动,然后 
click
horizontal move
 无法正常工作(移动设备上的水平滑动指的是 History.goback,我想阻止它我的手势需要它)。

总而言之:我想要的只是防止默认行为,垂直滚动除外。

对于如何实现这一目标有什么想法吗?或者还有其他想法/方法来实现这一目标吗?

HTML(只是多个项目的简单列表)

<div class="timeLineItemContainer"> <div class="subItemMiddleContainer"> <div class="timeLineHeader"> <div> <span>A TITLE</span> </div> <div> <div>Some other text text</div> </div> </div> </div> <div class="subItemBottomContainer"> <ul> <li class="static"> <div class="timeLineRight timeLineInfo"> <span class="info">Thu 12 March</span> </div> </li> <li class="static"> <div class="timeLineRight timeLineInfo"> <span class="label">some additional text</span> <span class="info time strikethrough">bla</span> <div class="info time attention"> <span>yup</span> </div> </div> </li> <li class="toggable closed"> <div class="timeLineRight timeLineInfo"> <span class="label">Text</span> <span class="info">content</span> </div> </li> <li class="toggable closed"> <div class="timeLineRight timeLineInfo"> <span class="label">title</span> <span class="info">value</span> </div> </li> <li class="toggable closed"> <div class="timeLineRight timeLineInfo"> <span class="label">Another title</span> <span class="info">another value</span> </div> </li> <li class="static"> <div class="timeLineRight timeLineInfo"> <span class="label">always visible</span> <span class="info time strikethrough">just because</span> <div class="info attention"> <span>attention!</span> </div> </div> </li> </ul> </div> </div> <div class="timeLineItemContainer"> <div class="subItemMiddleContainer"> <div class="timeLineLeft"> <div class="timeLinePipe"></div> </div> <div class="timeLineHeader"> <div> <span>Some other text</span> </div> <div> <div>Ola!</div> </div> </div> </div> <div class="subItemBottomContainer"> <ul> <li class="static"> <div class="timeLineRight timeLineInfo"> <span class="info">A date</span> </div> </li> <li class="toggable closed"> <div class="timeLineRight timeLineInfo"> <span class="label">label</span> <span class="info">value</span> </div> </li> <li class="toggable closed"> <div class="timeLineRight timeLineInfo"> <span class="label">anotehr label</span> <span class="info time">different value</span> </div> </li> </ul> </div> </div> <div class="timeLineItemContainer"> <div class="subItemMiddleContainer"> <div class="timeLineHeader"> <div> <span>A TITLE</span> </div> <div> <div>Some other text text</div> </div> </div> </div> <div class="subItemBottomContainer"> <ul> <li class="static"> <div class="timeLineRight timeLineInfo"> <span class="info">Thu 12 March</span> </div> </li> <li class="static"> <div class="timeLineRight timeLineInfo"> <span class="label">some additional text</span> <span class="info time strikethrough">bla</span> <div class="info time attention"> <span>yup</span> </div> </div> </li> <li class="toggable closed"> <div class="timeLineRight timeLineInfo"> <span class="label">Text</span> <span class="info">content</span> </div> </li> <li class="toggable closed"> <div class="timeLineRight timeLineInfo"> <span class="label">title</span> <span class="info">value</span> </div> </li> <li class="toggable closed"> <div class="timeLineRight timeLineInfo"> <span class="label">Another title</span> <span class="info">another value</span> </div> </li> <li class="static"> <div class="timeLineRight timeLineInfo"> <span class="label">always visible</span> <span class="info time strikethrough">just because</span> <div class="info attention"> <span>attention!</span> </div> </div> </li> </ul> </div> </div> <div class="timeLineItemContainer"> <div class="subItemMiddleContainer"> <div class="timeLineLeft"> <div class="timeLinePipe"></div> </div> <div class="timeLineHeader"> <div> <span>Some other text</span> </div> <div> <div>Ola!</div> </div> </div> </div> <div class="subItemBottomContainer"> <ul> <li class="static"> <div class="timeLineRight timeLineInfo"> <span class="info">A date</span> </div> </li> <li class="toggable closed"> <div class="timeLineRight timeLineInfo"> <span class="label">label</span> <span class="info">value</span> </div> </li> <li class="toggable closed"> <div class="timeLineRight timeLineInfo"> <span class="label">anotehr label</span> <span class="info time">different value</span> </div> </li> </ul> </div> </div>

Javascript

var sw = screen.width; var thresholdPercentageSwipeTimeLineItem = 15; var thresholdPercentageSwipeDetailScreen = 10; $(".timeLineItemContainer").draggable({ scroll: false, axis: "x", drag: function (event, ui) { if (ui.position.left < 0) { ui.position.left = 0; } else { if (calculateOffsetPercentage(ui.position.left) > thresholdPercentageSwipeTimeLineItem) { return false; }; } }, stop: function (event, ui) { $(this).animate({ left: 0, }, { duration: 200, queue: false }); } }).click(function () { var nextObjs = $(this).toggleClass("visible").find(".toggable"); $.each(nextObjs, function () { $(this).stop().animate({ height: "toggle", queue: false }).toggleClass("closed"); }); }); function calculateOffsetPercentage(screenValue) { return (100 / (sw / screenValue)); }
    
javascript jquery html mobile
2个回答
1
投票
我尝试了 OPs 解决方案,但我认为 jQuery UI

draggable

 自从您上次发表这篇文章以来可能已经发生了变化。在我的测试中,即使在完全删除 
jquery-ui-touch-punch.js
 之后,我发现拖动事件仍然被 jQuery UI 
draggable
 消耗。我不想深入研究 jQuery UI 代码并分叉库,所以我设计了一个相当简单的替代方案。

在我的场景中,我有一个收件箱列表,您可以将其项目向左或向右拖动以显示操作按钮。整个收件箱项目必须是可拖动的——因此不能选择使用拖动手柄。

如果触摸是在

draggable

元素内启动的,

jQuery 的 
draggable
 会阻止触摸屏上的垂直滚动。因此,如果屏幕上充满了可拖动的收件箱项目,那么用户就会陷入困境——无法向上或向下滚动。

对我有用的解决方案是测量光标垂直位置的任何变化,并使用

window.scrollBy

 手动滚动窗口相同的量:

var firstY = null; var lastY = null; var currentY = null; var vertScroll = false; var initAdjustment = 0; // record the initial position of the cursor on start of the touch jqDraggableItem.on("touchstart", function(event) { lastY = currentY = firstY = event.originalEvent.touches[0].pageY; }); // fires whenever the cursor moves jqDraggableItem.on("touchmove", function(event) { currentY = event.originalEvent.touches[0].pageY; var adjustment = lastY-currentY; // Mimic native vertical scrolling where scrolling only starts after the // cursor has moved up or down from its original position by ~30 pixels. if (vertScroll == false && Math.abs(currentY-firstY) > 30) { vertScroll = true; initAdjustment = currentY-firstY; } // only apply the adjustment if the user has met the threshold for vertical scrolling if (vertScroll == true) { window.scrollBy(0,adjustment + initAdjustment); lastY = currentY + adjustment; } }); // when the user lifts their finger, they will again need to meet the // threshold before vertical scrolling starts. jqDraggableItem.on("touchend", function(event) { vertScroll = false; });

这将非常模仿触摸设备上的本机滚动。


0
投票
成功了!

乍一看,似乎

$(".timeLineItemContainer").draggable({ ... });

 正在消耗所有事件,但实际上是 
jquery-ui-touch-punch.js
 阻止了一切。

jquery-ui-touch-punch.js

 的工作方式是阻止所有触摸事件结果执行默认行为。因此,我稍微调整了 
jquery-ui-touch-punch.js
 以获得正确的行为。

  1. 我从

    event.preventDefault()

     函数中删除了 
    simulateMouseEvent()

  2. 我将触摸的开始存储在

    mouseProto._touchStart

    事件中

    tsx = event.originalEvent.touches[0].clientX; tsy = event.originalEvent.touches[0].clientY;

  3. 我在

    mouseProto._touchMove

     事件中添加了一个条件来检查我是否在水平或垂直方向滚动。如果是水平方向,我将执行 
    event.preventDefault()
    。为此,您可以使用:

    // Higher then 1 means a (more) horizontal direction // Lower then 1 means a (more) vertical direction // 1 is an exact 45 degrees swipe, which will be handled as a vertical swipe if ((Math.abs(CurrentX - StartX)) / Math.abs(CurrentY - StartY) > 1) { event.preventDefault(); }

mouseProto._touchStart

mouseProto._touchMove
函数的最终结果如下所示:

var tsx = 0, tsy = 0, currentx = 0, currenty = 0; mouseProto._touchStart = function (event) { var self = this; tsx = event.originalEvent.touches[0].clientX; tsy = event.originalEvent.touches[0].clientY; // Ignore the event if another widget is already being handled if (touchHandled || !self._mouseCapture(event.originalEvent.changedTouches[0])) { return; } // Set the flag to prevent other widgets from inheriting the touch event touchHandled = true; // Track movement to determine if interaction was a click self._touchMoved = false; //// Simulate the mouseover event simulateMouseEvent(event, 'mouseover'); //// Simulate the mousemove event simulateMouseEvent(event, 'mousemove'); // Simulate the mousedown event simulateMouseEvent(event, 'mousedown'); }; mouseProto._touchMove = function (event) { // Ignore event if not handled if (!touchHandled) { return; } // Higher then 1 means a (more) horizontal direction // Lower then 1 means a (more) vertical direction // 1 is an exact 45 degrees swipe, which will be handled as a vertical swipe if ((Math.abs(event.originalEvent.changedTouches[0].clientX - tsx)) / Math.abs(event.originalEvent.changedTouches[0].clientY - tsy) > 1) { event.preventDefault(); } // Interaction was not a click this._touchMoved = true; // Simulate the mousemove event simulateMouseEvent(event, 'mousemove'); };
    
© www.soinside.com 2019 - 2024. All rights reserved.