2012-05-08 80 views
7

我正在爲使用Jquery和Jquery Mobile的Android開發PhoneGap應用程序。jquery在taphold事件後調用點擊事件

我有一個需要列表中每個項目綁定兩個事件的項目列表。我需要一個「taphold」事件和一個「點擊」事件。我遇到的問題是,當我做一個「拉桿」時,正確的「拉桿」事件被解僱。但是,一旦我釋放,click事件也會被觸發。我怎樣才能防止點擊事件在拉籃後觸發?

代碼:

function LoadMyItems(items) { 

for(var idx in items) 
{ 
    var itemLine = '<div class="my_item" id="my_item_'+items[idx].user_item_id+'">' + 
      '<img class="item_icon_32" src=./images/graphicFiles/Icon48/'+items[idx].item.graphic.graphicFiles.Icon48.filename+' />' + 
      items[idx].item.name+  
      '</div>'; 
    $('#my_list').append('<li>'+itemLine+'</li>'); 
     $('#my_item_'+items[idx].user_item_id).bind('taphold', {userItem:items[idx]},ShowMyItemInfo); 
     $('#my_item_'+items[idx].user_item_id).bind('click tap', {userItem:items[idx]},FitMyUpgradeItem); 
     console.log('UserItem '+items[idx].user_item_id+' loaded and events bound'); 
    } 
    $('#my_items_loader').hide(); 
    myScroll.refresh(); 
} 

下面的意見後,這是我結束了。這適用於iScroll對象。

function LoadMyItems(items) { 

for(var idx in items) 
{ 
    var itemLine = '<div class="my_item" id="my_item_'+items[idx].user_item_id+'">' + 
        '<img class="item_icon_32" src=./images/graphicFiles/Icon48/'+items[idx].item.graphic.graphicFiles.Icon48.filename+' />' + 
        items[idx].item.name+  
        '</div>'; 
    $('#my_list').append('<li>'+itemLine+'</li>'); 

    (function(index) { 
     var tapTime = 0; 
     var xPos = 0; 
     var yPos = 0; 
     $('#my_item_'+items[index].user_item_id).bind('vmousedown vmouseup', function (event) { 
      if (event.type == 'vmousedown') { 

       tapTime = new Date().getTime(); 
       xPos = event.pageX; 
       yPos = event.pageY; 

       var timer = setTimeout(function() { 
        var duration = (new Date().getTime() - tapTime); 
        var xDiff = Math.abs(mouseXPos - xPos); 
        var yDiff = Math.abs(mouseYPos - yPos); 
        if(duration >= 700 && (yDiff <= 40 || mouseXPos == 0)) 
         ShowItemInfo(items[index].item); 
       },750); 
      } else { 
       //event.type == 'vmouseup' 
       var duration = (new Date().getTime() - tapTime); 
       var xDiff = Math.abs(event.pageX - xPos); 
       var yDiff = Math.abs(event.pageY - yPos); 
       tapTime = new Date().getTime(); 
       if (duration < 699 && yDiff <= 40) { 
        //this is a tap 
        FitMyUpgradeItem(items[index]); 
       } 
      } 
     }); 

     $('#my_item_'+items[index].user_item_id).bind('touchmove',function(event) { 
      event.preventDefault(); 
     }); 
    })(idx); 

    console.log('UserItem '+items[idx].user_item_id+' loaded and events bound'); 
} 
$('#my_items_loader').hide(); 
myScroll.refresh(); 
} 
+0

屢試不爽快速解決方案: http://stackoverflow.com/a/11941654/1386781 –

回答

12

而不是使用taptaphold(我已經嘗試使用,但遇到了同樣的問題,這似乎是與taphold事件固有的問題),你可以使用vmousedown並設置一個標誌,則結合至vmouseup以確定它是否是一個taptaphold

var tapTime = 0; 
$('#my_item_'+items[idx].user_item_id).bind('vmousedown vmouseup', function (event) { 
    if (event.type == 'vmousedown') { 
     tapTime = new Date().getTime(); 
    } else { 
     //event.type == 'vmouseup' 
     //here you can check how long the `tap` was to determine what do do 

     var duration = (new Date().getTime() - tapTime); 
     if (duration > 3000) { 
      //this is a tap-hold 
      ShowMyItemInfo(items[idx]); 
     } else { 
      //this is a tap 
      FitMyUpgradeItem(items[idx]); 
     } 
    } 
}); 

爲了能夠正常工作,您必須在循環代碼周圍添加IIFE或更改ShowMyItemInfo(items[idx]);以在不更改每次迭代循環的變量的情況下工作。一個簡單的創建一個IIFE就是使用$.each()。否則你的循環看起來像這樣:

for(var idx in items) 
{ 
    (function (idx) { 
     ... 
    })(idx); 
} 

IIFE =立即調用函數表達式。它使我們能夠對我們傳遞給IIFE的變量的當前狀態進行「快照」。因此,我們通過idx(技術上第二個實例是傳入的變量,第一個實例是IIFE內部可用的變量,爲簡單起見可以將其更改爲類似ids_new),傳入的值將被保存當事件處理程序觸發時。

更新

您還可以設置超時,以確定taphold,而不是使用vmouseup事件:

//setup a timer and a flag variable 
var tapTimer, 
    isTapHold = false; 
$('#my_item_'+items[idx].user_item_id).bind('vmousedown vmouseup', function (event) { 
    if (event.type == 'vmousedown') { 

     //set the timer to run the `taphold` function in three seconds 
     // 
     tapTimer = setTimeout(function() { 
      isTapHold = true; 
      ShowMyItemInfo(items[idx]); 
     }, 3000); 
    } else { 
     //event.type == 'vmouseup' 
     //clear the timeout if it hasn't yet occured 
     clearTimeout(tapTimer);  

     //if the flag is set to false then this is a `tap` event 
     if (!isTapHold) { 
      //this is a tap, not a tap-hold 
      FitMyUpgradeItem(items[idx]); 
     } 

     //reset flag 
     isTapHold = false; 
    } 
}); 

通過這種方式,用戶按住自己的手指三秒鐘後,該事件將觸發。然後,如果三秒鐘沒有發生,那麼tap事件處理程序只會觸發。

$.event.special.tap.emitTapOnTaphold = false; 

然後你可以使用它像這樣:

+0

好吧,這個偉大的作品。非常感謝。我現在唯一的問題是如何使這是一個真正的水龍頭,而不是輕拍,按住,釋放。我希望它像taphold事件一樣工作。所以在〜750ms之後,觸發該功能以完成taphold – jasonlg3d

+0

@ jasonlg3d我添加了一個如何使用超時功能來執行此操作的示例,因此它不會讓用戶舉起手指進行反饋。查看**更新**到我的答案。 – Jasper

+0

我當時正在研究這個問題。我上面發佈了我的解決方案我不得不做一些額外的事情,以確保iScroll仍然滾動,並沒有脫離taphold事件。 – jasonlg3d

0

使用tap \ vclick和taphold取而代之 - 點擊事件在拉籃後會被觸發兩次。

$('#my_item_'+items[idx].user_item_id).bind('vclick', ... 
$('#my_item_'+items[idx].user_item_id).bind('taphold', ... 

在這個例子中點擊實際上不是taphold後調用。檢查在這裏:http://jsfiddle.net/YL8hj/43/

編輯:

jQuery Mobile的自動綁定觸摸事件的一些元素。當 將iScroll與jQuery Mobile相結合時,將一個 單獨函數綁定到「touchmove」事件並阻止從 冒泡(event.preventDefault())事件可能是一個好主意。通過這樣做,當用戶使用iScroll元素與 進行交互時,jQuery Mobile 將無法​​處理觸摸事件。

http://appcropolis.com/blog/jquery-wrapper-for-iscroll/ 信貸https://stackoverflow.com/a/9408567/643500

+0

我試過了,它似乎是做同樣的事情。 :/這些項目位於iScroll對象內部。我想知道這是否導致問題? – jasonlg3d

+0

好的,我試過設備上的jsfiddle鏈接,它不能正常工作。所有事件都會在android webview中觸發。所以這是一個設備問題。我需要想出一個不同的方式來設置這些事件... – jasonlg3d

+0

請再次嘗試jsfiddle。我離開了水龍頭,點擊和vclick只是爲了顯示不同之處。 –

5

定義之前,您甚至只需將此設置爲您的文檔的頂部或任何

$('#button').on('tap',function(){ 
    console.log('tap!'); 
}).on('taphold',function(){ 
    console.log('taphold!'); 
}); 
+0

這是一般事件的最佳答案... – Group

+0

謝謝,最佳答案 –

1

就個人而言,我認爲答案在這裏大大過度複雜的問題。如果你只是想要一個簡單的方法就可以繼續使用taphold事件,而忽略當你發佈一個taphold觸發該點擊事件,以下是我在我自己的項目解決了這個同樣的問題:

// We will use this flag to ignore click events we don't want 
var skipNextClick = false; 

//Set up your event handler. You could do these using two handlers or one. I chose one. 

$('div.element').on('click taphold', function (e) { 
    //set up a quick bool flag that is true if click 
    var isClick = (e.type == 'click'); 

    if (isClick && !skipNextClick) { 
     //run your code for normal click events here... 

    } 
    else if (isClick && skipNextClick) { 
     //this is where skipped click events will end up... 

     //we need to reset our skipNextClick flag here, 
     //this way, our next click will not be ignored 
     skipNextClick = false; 
    } 
    else { 
     //taphold event 

     //to ignore the click event that fires when you release your taphold, 
     //we set the skipNextClick flag to true here. 
     skipNextClick = true; 

     //run your code for taphold events here... 

    } 
}); 
+0

如果您在釋放之前移出元素,那麼taphold事件仍會觸發。如果你這樣做,下一個點擊事件將被跳過,因爲當你移出元素時,點擊事件沒有被正確地觸發。 – Jules

+0

我完全可以看到會發生什麼!有幾種方法可以解決這個問題。也許查找touchstart事件,記下它開始的元素,然後查找相應的touchend事件並查看它是否在原始元素或父級之外。 –

+0

...或者jQuery mobile應該正確實施tap/taphold,以便在釋放之前移動到元素外部時不會觸發 – Jules