[英]How to detect touchend event outside of an element
我正在嘗試處理按鈕點擊。 “按鈕”是一個自定義div,也可以包含子項。 當用戶在元素內單擊並釋放時,應觸發單擊回調。 如果用戶單擊內部然后拖動並釋放到外部,則處理程序不應該觸發。 我需要在桌面和移動設備上使用它,因此我正在使用mousedown/mouseup
和touchstart/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中進行了測試,當按下元素時,然后拖出“Inside!” 警報顯示。
問題出在這種情況:
if ($target.is($myElement) || $target.parents().is($myElement)){
我正在嘗試檢查按鈕或任何一個孩子是否發生了touchend
事件。 如果按鈕沒有子節點,則單擊它然后釋放到外部時,OR子句的第一部分將解析為true。 如果按鈕有子項並且我單擊子項,然后在屏幕的任何其他部分釋放,則該子句的第二部分為真。
這段代碼有什么問題?
提前致謝。
UPDATE
我也在BlackBerry 10中對它進行了測試,結果相同。 顯然, touchend
事件的目標是按鈕(或孩子們),即使我在外面點擊也是如此。 這是它應該如何工作?
UPDATE
這就是原因。 這就是W3C文檔對此事件的評價 :
此觸摸事件的目標必須與此觸摸點放置在曲面上時觸摸touchstart事件的元素相同,即使觸摸點已移出目標元素的交互區域之外。
這對我沒有意義,但無論如何這解釋了我的問題。 我假設在手指被釋放的元素上調用touchend
事件。 是否可以使用不同的方法檢測外部的手指釋放?
UPDATE
我試圖使用document.elementFromPoint
獲取touchevent
的坐標以獲取元素。 問題是此事件不包含坐標( changedTouches
和touches
列表為空)。 我已經徹底檢查了調試器中的事件,除了原始事件之外,沒有辦法從中檢索coords。 然后我想我可以緩存最后一次touchmove
事件並從那里獲得coords,但是這個事件再次沒有自己的坐標! 為什么地球上這兩個事件存在時它們是無用的? 我已經在iOS,Android和BB10中測試了這種方法,結果相同。
我已經放棄了。 即使用戶點擊外面,我也會調用回調。 我不敢相信它是2013年的家伙而且沒有(簡單)這樣做的方式? 我可以使用拖放API,但根據這是在移動(愛是愛移動Web開發)不支持的。
最后(幾乎)讓它在BB10和Android中運行。 我離開的問題更新問題線索,所以綜上所述: touchend
事件目標是一樣的touchstart
,並談到無坐標(出於某種原因,API設計師決定在“隱藏”他們originalEvent
財產:)。 所以我從changedTouches[0].pageX
和changedTouches[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中某種程度上,點擊事件是重復的。 但這值得一個不同的問題(如果不存在的話)。
你需要一個不同的,更整潔的方法。
分別為桌面和移動設備實現onmousemove和ontouchmove。
btn_obj.onmousemove = CancelOnClick (this);
實現CancelOnClick函數將標志從按下設置為正常。 它可以幫助您遠離所有元素及其基於子元素的條件。
希望有所幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.