Подтвердить что ты не робот

Как заставить touchEnd вести себя так же, как mouseUp?

В mouseUp или touchEnd Я хочу получить ссылку на элемент, в котором произошло это событие.

Демо

В этом примере вам нужно щелкнуть по одному элементу, перетащить мышь и отпустить над другим элементом. Когда мышь будет выпущена, этот фон элемента изменится на красный. Мой код работает правильно для событий мыши, но не на сенсорных устройствах.

Когда touchStart находится на одном элементе, а палец выпущен над другим элементом, я получаю только ссылку на первый элемент.

Что мне нужно изменить, чтобы события касания работали точно так же, как события мыши?

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";        

}
4b9b3361

Ответ 1

Это был забавный вопрос. Спасибо за это. Вот что я сделал. Я изменил ваш обработчик touchmove как таковой:

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

В этом обработчике я сохраняю последнюю координату, к которой пользователь переместился. По всей вероятности, это тот момент, когда пользователь взял свой палец, нос, сустав, стилус и т.д. С поверхности касания. Эти координаты я затем использую в обработчике для touchend, чтобы найти элемент, который их окружает.

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

Я использовал для этой цели document.elementFromPoint (mdn link). Это один из тех золотых, но довольно неизвестных методов, предоставленных нам спецификацией CSSOM.

Здесь fiddle.

Ответ 2

Из того, что кажется, это предназначенное поведение для сенсорных событий. Однако у меня есть обходной путь!

Я не тестировал это широко, но, похоже, работает на мобильном Safari для не менее touchStart и touchEnd событий.

В основном, что мы собираемся делать, это захватить все события касания документа, поскольку они находятся в фазе захвата (см. http://www.w3.org/TR/DOM-Level-3-Events/), Обработчик этих событий найдет элемент DOM в этом месте и повторно отправит событие с "правильной" целью.

Кажется, что позиция событий touchEnd не определена, поэтому мне пришлось запросить массив changedEvents, чтобы получить последнее касание. Я не уверен, что это работает как есть для событий touchMove и других.

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

Здесь jsfiddle, который работает на мобильном сафари для меня: http://jsfiddle.net/DREer/12/

Ответ 3

Возможно, если вы можете включить jQuery в свою программу, вы можете сделать что-то вроде этого:

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

Я не уверен, что jQuery из коробки поддерживает эти события, но вы всегда можете попробовать jQuery movil, надеюсь, что это помогло