2013-05-22 9 views
5

Ich habe Probleme mit der Kombination von CSS-Transformationen und Touch-Event-Hit-Tests. Dies reproduziert nur für mich in Chrome auf Android 4 (stabil und Beta). iOS Safari, sowie Chrome Desktop mit Touch-Emulation scheinen beide gut zu funktionieren.Android 4 Chrome Hit Test-Problem bei Touch-Ereignissen nach CSS-Transformation

Ich bin fast sicher, dass dies ein Bug sein muss, also denke ich, dass ich hier hauptsächlich nach Workarounds suche.

Das Problem ist, dass Treffer-Test nur für Touch funktioniert, wo das Element vor der Transformation war, nicht die endgültige Position. Sie können ein Beispiel auf meinem jsfiddle (nur auf Android 4 Chrome) siehe:

jsfiddle: http://jsfiddle.net/LfaQq/ Vollbild: http://jsfiddle.net/LfaQq/embedded/result/

Wenn Sie das blaue Feld auf halbem Weg nach unten den Bildschirm und lassen Sie ziehen wird es zurückschnappen zu die Spitze. Wenn Sie nun versuchen, erneut von der oberen Hälfte der Seite zu ziehen, wird keine Berührung registriert. Die Berührungsereignisse werden nicht einmal auf dem Element ausgelöst. Wenn Sie jedoch versuchen, die Unterseite des Elements zu berühren, funktioniert es einwandfrei. Sie können dann versuchen, es von unten nach oben zu bewegen, und beobachten, dass der Treffertest nicht mehr auf der Unterseite, sondern auf der Oberseite funktioniert.

Dies ist, wie ich die Ereignisse bin Umgang:

function handleTouch(e) { 

    console.log("handle touch") 

    e.preventDefault(); 

    switch(e.type){ 
     case 'touchstart': 
      console.log("touchstart"); 
      touchOriginY = e.targetTouches[0].screenY; 
      break; 
     case 'touchmove': 
      console.log("touchmove"); 
      el.innerHTML = e.targetTouches[0].screenY; 
      var p = e.targetTouches[0].screenY - touchOriginY; 
      el.style[TRANSFORM] = 'translate3d(0,' + p + 'px' + ',0)'; 
      break; 
     case 'touchcancel': 
      console.log("touchcancel"); 
      // Fall through to touchend 
     case 'touchend': 
      //console.log("touchend"); 
      //el.style[TRANSITION] = '.4s ease-out'; 
      el.style[TRANSFORM] = 'translate3d(0,0,0)'; 
      break; 
    } 

} 

el.addEventListener('touchstart', handleTouch); 
el.addEventListener('touchend', handleTouch); 
el.addEventListener('touchmove', handleTouch); 
el.addEventListener(TRANSITION_END, function(e) { 
    console.log("transition end") 
    el.style[TRANSITION] = ''; 
}); 

ich mit den Transformationen in Berührungsbewegungs Probleme nicht haben, als diejenigen, die nicht neu berührt sind sowieso erkannt werden.

Irgendwelche Vorschläge?

+0

Ich denke, ich habe mich vorerst auf diese Weise etwas entblockt. Durch das Entfernen des innerHTML-Updates von touchmove wird die Trefferzielschädigung gestoppt. Ich hoffe, dass es mich nicht zurückhält, wenn ich den Inhalt später wirklich aktualisieren muss. –

Antwort

8

Dies ist ein ungewöhnlicher Fehler in Chrome.

Im Wesentlichen werden die Trefferziele für ein Element während eines Layoutdurchlaufs vom Browser aufgezeichnet. Jedes Mal, wenn Sie innerHTML setzen, wird der Browser neu angezeigt und das letzte Mal, bevor dies gemacht wird, bevor das Ereignis touchend ausgelöst wird. Dafür gibt es verschiedene Möglichkeiten:

OPTION 1: Sie können einen Berührungshandler für das Körperelement festlegen und das Ziel des Berührungsereignisses überprüfen, um festzustellen, ob es den roten Block berührt. Spitze der Kappe zu Paul Lewis für diesen Ansatz.

http://jsfiddle.net/FtfR8/5/

var el = document.body; 
var redblock = $('.splash-section'); 

function handleTouch(e) { 

    console.log("handle touch") 
    if(e.target != redblock) { 
     return; 
    } 

    .... 

OPTION 2: Stellen Sie einen leerer Touch-Rückruf auf dem Dokument, das Problem auch zu beheben scheint - nach einigen der verknüpften Fehlerberichte, dies bewirkt, dass die Treffertests auf die getan werden Hauptthread, der die Leistung beeinträchtigt, aber die Trefferziele richtig berechnet.

http://jsfiddle.net/LfaQq/2/

document.body.addEventListener('touchstart', function(){}); 

OPTION 3: Set innerHTML- nach dem Übergang ein Neu-Layout zu erzwingen beendet:

el.addEventListener(TRANSITION_END, function(e) { 
    console.log("trans end - offsettop:" + el.offsetTop); 
    el.style[TRANSITION] = ''; 
    el.innerHTML = 'Relayout like a boss!'; 
}); 

Ich habe einen Bug-Report hier und Rick Byers hat zu einem verwandten verknüpft erstellt Bug mit zusätzlichen Informationen: https://code.google.com/p/chromium/issues/detail?id=253456&thanks=253456&ts=1372075599

+1

Die "OPTION 2" funktioniert wie ein Zauber, danke. –