2012-07-11 34 views
13

En mouseUp o touchEnd Quiero obtener la referencia del elemento en el que ocurrió ese evento.¿Cómo obtener touchEnd para comportarse como mouseUp?

Demo

En este ejemplo, es necesario hacer clic en un elemento, arrastre con el ratón y lanzado sobre otro elemento. Cuando se suelta el mouse, el fondo de ese elemento cambiará a rojo. Mi código funciona correctamente para los eventos del mouse, pero no en los dispositivos táctiles.

Cuando el touchStart está en un elemento y el dedo se suelta sobre otro elemento, obtengo solo la referencia al primer elemento.

¿Qué necesito cambiar para que los eventos táctiles funcionen exactamente como los eventos del mouse?

var isMouseDown = false;  


var panel1 = document.getElementById('panel1'); 
var panel2 = document.getElementById('panel2'); 

panel1.onmousedown = onDocumentMouseDown; 
panel1.onmouseup = onDocumentMouseUp; 
panel1.onmousemove = onDocumentMouseMove; 
panel1.addEventListener('touchstart', onDocumentTouchStart, false); 
panel1.addEventListener('touchmove', onDocumentTouchMove, false); 
panel1.addEventListener('touchend', onDocumentTouchEnd, false); 

panel2.onmousedown = onDocumentMouseDown; 
panel2.onmouseup = onDocumentMouseUp; 
panel2.onmousemove = onDocumentMouseMove; 
panel2.addEventListener('touchstart', onDocumentTouchStart, false); 
panel2.addEventListener('touchmove', onDocumentTouchMove, false); 
panel2.addEventListener('touchend', onDocumentTouchEnd, false); 



function onDocumentMouseDown(event) { 
    event.preventDefault(); 
    panel1.style.background="#2E442E"; 
    panel2.style.background="#5D855C";  
} 

function onDocumentMouseUp(event) { 
    event.preventDefault(); 
    this.style.background="#ff0000"; 
} 

function onDocumentMouseMove(event) { 

} 

function onDocumentTouchStart(event) { 
    event.preventDefault(); 
    panel1.style.background="#2E442E"; 
    panel2.style.background="#5D855C"; 

} 

function onDocumentTouchMove(event) {  

} 

function onDocumentTouchEnd(event) { 
    event.preventDefault();   
    this.style.background="#ff0000";   

} 
+0

qué dispositivos táctiles ha probado (medio) – shareef

+0

** Pregunta similar ** [¿Cómo averiguar el evento real.target of touchmove javascript event?] (Http://stackoverflow.com/q/3918842/351708) – Rohit

Respuesta

11

Esta fue una pregunta divertida de abordar. Gracias por eso. Esto es lo que hice. He modificado el controlador touchmove como tal:

function onDocumentTouchMove(event) { 
    onDocumentTouchMove.x = event.changedTouches[event.changedTouches.length - 1].clientX; 
    onDocumentTouchMove.y = event.changedTouches[event.changedTouches.length - 1].clientY; 
} 

En este controlador Estoy ahorrando el último de coordenadas que el usuario se trasladó a. Con toda probabilidad, este es el punto en el que el usuario quitó su dedo, nariz, nudillo, lápiz, etc. de la superficie táctil. Estas coordenadas luego las uso en el controlador para touchend para encontrar el elemento que las rodea.

function onDocumentTouchEnd(event) { 
    event.preventDefault(); 
    var elem = document.elementFromPoint(onDocumentTouchMove.x, onDocumentTouchMove.y); 
    elem.style.background = "#ff0000"; 
} 

que han utilizado el document.elementFromPoint(mdn link) para este propósito. Es uno de esos métodos dorados pero bastante desconocidos que nos brindó el CSSOM spec.

Aquí está el fiddle.

+1

¡Un gran hallazgo! Puedo confirmar que esto funciona en un Samsung Galaxy Tab con Chrome. –

+0

También funciona en opera, stock android browser y chrome en mi one x. – zeusdeux

+0

yup .. creo que esta es una buena solución ... :) pero no sé cuál es el soporte para elementFromPoint .. – Sarath

-1

Tal vez si usted puede incluir en su programa de jQuery que puede hacer algo como esto:

$('#itemId').on('touchEnd',function(){ this.trigger('mouseUp') }); 

No estoy seguro de si jQuery fuera de la caja es compatible con este tipo de eventos, pero siempre se puede prueba jQuery movil, espero que haya ayudado

+0

no puedo incluir jquery ... pero esto también dará el mismo resultado. – Sarath

+0

@isaac 'this' aquí seguirá siendo el elemento donde' touchstart' se activó, por lo tanto, no es una solución viable. – zeusdeux

0

De lo que parece, este es el comportamiento previsto para los eventos táctiles. Sin embargo, tengo una solución!

No he probado esto extensamente, pero parece funcionar en Safari móvil para al menos touchStart y touchEnd eventos.

Básicamente lo que vamos a hacer es capturar todos los eventos táctiles en el documento, ya que están en fase de captura (ver http://www.w3.org/TR/DOM-Level-3-Events/). El controlador de estos eventos encontrará el elemento DOM en esta ubicación y volverá a enviar el evento con el objetivo "correcto".

Parece que la posición de los eventos touchEnd no está bien definida, por lo que tuve que consultar la matriz changedEvents para obtener la última posición tocada. No estoy seguro si esto funciona como está para touchMove events et al.

function rerouteTouch (evt) { 
    if (evt.passthrough) { // Ignore if already rerouted 
     return; 
    } 
    evt.stopPropagation(); 
    var newevt = document.createEvent('TouchEvent'); 
    newevt.initTouchEvent (
     evt.type, 
     evt.bubbles, 
     evt.cancelable, 
     evt.view, 
     evt.detail, 
     evt.screenX, 
     evt.screenY, 
     evt.clientX, 
     evt.clientY, 
     evt.ctrlKey, 
     evt.altKey, 
     evt.shiftKey, 
     evt.metaKey, 
     evt.touches, 
     evt.targetTouches, 
     evt.changedTouches, 
     evt.scale, 
     evt.rotation); 
    newevt.passthrough = true; // Only reroute once 

    var target; 
    var x = (evt.type === 'touchend') ? evt.changedTouches[0].pageX : evt.pageX; 
    var y = (evt.type === 'touchend') ? evt.changedTouches[0].pageY : evt.pageY; 

    if (document !== (target = document.elementFromPoint(x, y))) { 
     target.dispatchEvent(newevt); 
    } 
} 

document.addEventListener('touchstart', rerouteTouch, true); // Third arg is true to indicate capture-phase 
document.addEventListener('touchend', rerouteTouch, true); 

... 

// Your event handlers here 

Aquí hay una jsFiddle que funciona como se esperaba en Safari Mobile para mí: http://jsfiddle.net/DREer/12/

Cuestiones relacionadas