如何检测元素外的touchend事件

时间:2013-07-15 08:49:54

标签: javascript jquery html5 mobile touch

我试图处理按钮点击。 "按钮"是一个自定义div,也可以包含儿童。当用户在元素内单击并释放时,应触发单击回调。如果用户单击内部然后拖动并释放到外部,则处理程序不应该触发。我需要在桌面设备和移动设备上使用它,因此我使用mousedown/mouseuptouchstart/touchend事件。

我需要更改"按下"到"正常"即使用户在外面发布,我也需要添加一个监听器来捕获文档上的发布事件:

    var $myElement = $("#myelement"); //This is a div and can also contain children.

    $myElement.on("mousedown touchstart", function(e){  

        $(this).addClass("pressed");    

        $(document).on("mouseup touchend", function listener(e){
            $myElement.removeClass("pressed");

            $(document).off("mouseup touchend", listener);

            var $target = $(e.target);
            if ($target.is($myElement) || $target.parents().is($myElement)){        
                //FIXME
                alert("Inside!");

                //do something here
                return false;
            } else {
                //FIXME
                alert("Outside!");

                //let event bubble
            }
        });

        return false;
    });

点击可以正常使用,但触摸事件无法正常工作。我已经在Chrome for Android中对此进行了测试,当按下元素时,然后将其拖出,内部!"警报显示。

问题出在这种情况:

if ($target.is($myElement) || $target.parents().is($myElement)){

我试图检查按钮或任何一个孩子是否发生了touchend事件。如果按钮没有子节点,则单击它然后释放到外部时,OR子句的第一部分将解析为true。如果按钮有子项并且我单击子项,然后在屏幕的任何其他部分中释放,则该子句的第二部分为真。

此代码有什么问题?

先谢谢。

UPDATE
我也在BlackBerry 10中对它进行了测试,结果相同。显然,touchend事件的目标是按钮(或孩子),即使我在外面点击也是如此。这是应该如何工作的吗?

UPDATE
这就是原因。这是what the W3C docs say about the event

  

当此触摸点放置在曲面上时,此事件的目标必须与接收touchstart事件的元素相同,即使触摸点已移出目标元素的交互区域之外。

这对我没有意义,但无论如何这解释了我的问题。我假设将在释放手指的元素上调用touchend事件。是否可以使用不同的方法检测外部的手指释放?

UPDATE
我尝试使用touchevent获取document.elementFromPoint的坐标以获取元素。{1}}问题是此事件不包含坐标(changedTouchestouches列表为空)。我已经彻底检查了调试器中的事件,并且除了原始事件之外,没有办法从中检索出协调。然后我想我可以缓存最后的touchmove事件并从那里获取坐标,但是这个事件再次没有自己的坐标!为什么地球上这两个事件存在时它们是无用的?我已经在iOS,Android和BB10中对此方法进行了测试,结果相同。

我已经放弃了。即使用户在外面点击,我也会打电话给回叫。我无法相信这是2013年的人,而且这样做没有(简单)方法吗?我可以使用拖放api但是根据this,它在移动设备上不受支持(喜欢移动网络开发)。

2 个答案:

答案 0 :(得分:8)

最后(几乎)让它在BB10和Android中运行。我在问题更新中留下了一些问题,所以总结一下:touchend事件目标与touchstart相同,它没有坐标(由于某种原因决定了API设计者)将它们“隐藏”在originalEvent属性:)中。所以我正在从changedTouches[0].pageXchangedTouches[0].pageY检索触摸结束坐标,然后使用document.elementFromPoint获取释放手指的元素。 (在使用事件坐标输入此方法之前,必须将滚动偏移添加到x和y)。然后,如果该点的元素是按钮(或者是它的子元素),我处理点击。

    var $myElement = $("#myelement"); //This is a div and can also contain children.
    var startEvent = touchDevice() ?  "touchstart" : "mousedown";
    var releaseEvent = touchDevice() ?  "touchend" : "mouseup";

    $myElement.on(startEvent, function(e){  

        $(this).addClass("pressed");    

        $(document).on(releaseEvent, function listener(e){
            $myElement.removeClass("pressed");

            $(document).off(releaseEvent, listener);

            var $target = null;
            if(e.type === "mouseup"){
                 $target = $(e.target);         
            } else {            
                var x = e.originalEvent.changedTouches[0].pageX - window.pageXOffset;
                var y = e.originalEvent.changedTouches[0].pageY - window.pageYOffset;
                var target = document.elementFromPoint(x, y);

                if(target){
                    $target = $(target);
                }           
            }

            if ($target !== null && ($target.is($myElement) || $target.parents().is($myElement))){      
                //FIXME
                alert("Inside!");

                //callback here
                return false;
            } else {
                //FIXME
                alert("Outside!");
            }
        });

        return false;
    });

现在我遇到了一个新问题:在iOS中某些方面,点击事件正在重复。但这值得一个不同的问题(如果不存在的话)。

答案 1 :(得分:1)

你需要一种不同的,更整洁的方法。

分别为桌面设备和移动设备实施onmousemove和ontouchmove。

btn_obj.onmousemove = CancelOnClick (this);

实现CancelOnClick函数将标志从按下设置为正常。它可以帮助您避免所有元素及其基于子元素的条件。

希望有所帮助。