stopPropagation() с событием касания

Я использую hammer.js, и кажется, что я event.stopPropagation() не работаю с нажатием мероприятие.

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

$('#parent').hammer().bind('tap', function(e) {
    $(this).css('background', 'red');
});​​​​​​​​

$('#child').hammer().bind('tap', function(e) {
    e.stopPropagation();
    $(this).css('background', 'blue');
});

Вот пример: http://jsfiddle.net/Mt9gV/

Я также пробовал с jGestures, и проблема, похоже, та же. Как я могу добиться этого результата с одной из этих библиотек? (или другой, если нужно)


person TimPetricola    schedule 13.06.2012    source источник
comment
Я думаю, это может иметь какое-то отношение к тому факту, что вы настроили молоток как для родительского, так и для дочернего элементов. Однако я не уверен на 100%.   -  person Pointy    schedule 13.06.2012
comment
К сожалению, если я не применю молоток к обоим элементам, событие касания не сработает.   -  person TimPetricola    schedule 13.06.2012


Ответы (5)


Как упоминалось в другом комментарии, можно было бы ожидать, как и вы, что вызов event.stopPropagation() будет всем, что требуется, чтобы предотвратить всплытие события до родителя.

Подробности. Однако в Hammer.js это не так. Hammer создает новый конечный автомат жеста для каждого элемента, для которого вы вызываете $(el).hammer(). Таким образом, когда браузер запускает сенсорное событие для дочернего элемента, оно сначала обрабатывается логикой для дочернего элемента, а затем снова логикой для родителя. Таким образом, чтобы запретить родительскому элементу получать событие tap, вы должны запретить конечному автомату молотка родителя получать исходное событие касания. Как правило, вызов event.stopPropagation() также останавливает распространение исходного события. Однако событие tap в Hammer.js запускается для touchend, но originalEvent является кэшированным событием touchstart. Таким образом, остановка распространения исходного события не имеет никакого эффекта, потому что событие touchstart уже давно всплыло в DOM.

Решение? Я считаю, что это ошибка в молотке. Отправьте запрос на вытягивание, который исправляет originalEvent в событии касания. Как предлагали другие, вы можете проверить цель события, но это всегда родительский элемент - на мой взгляд, еще одна ошибка. Поэтому вместо этого проверьте файл event.originalEvent.target. Вот скрипка JS с этим посредственным решением: http://jsfiddle.net/HHRHR/

person rharper    schedule 03.08.2012
comment
Примечание. Мой ответ на этот вопрос устарел — с момента публикации Hammer.js претерпел значительные изменения. - person rharper; 19.06.2013
comment
Мы используем код, почти идентичный исходному фрагменту TimPetricola. Я могу подтвердить, что он работает должным образом с Hammer.JS - v1.0.5 - 2013-04-07. Похоже, Hammer.js серьезно отнесся к этой проблеме и исправил ее. - person Douwe; 19.07.2013

Поскольку я не мог получить эту работу, я использовал переменную, чтобы узнать, было ли уже запущено дочернее событие. Он неплохо работает с jGestures (я не пробовал с Hammer.js)

var childTriggered = false;

$('#child').bind('tapone', function(e) {
    $(this).css('background', 'red');
    childTriggered = true;
});

$('#parent').bind('tapone', function(e) {
    if(childTriggered) {
        childTriggered = false;
        return;                
    }
    $(this).css('background', 'blue');
});

person TimPetricola    schedule 14.06.2012

У меня были аналогичные проблемы с сенсорными событиями.

Я решил это с помощью

return false;

что аналогично вызову e.preventDefault(); e.stopPropagation();

person Leo    schedule 01.08.2014

Если вы не можете заставить это работать ... просто вызовите другой метод на кране после проверки необходимости (arguments.callee - это то, с чего я бы начал в таком случае), это будет иметь дополнительные преимущества, позволяя другим пользователям также зацепить кнопку. ..

function myFn(a) { if(a) $(this).css('background', 'red'); else $(this).css('background', 'blue');}

$('#parent').hammer().bind('tap', function(e) {
   //Check arguments.callee or other data in event and call myFn
});​​​​​​​​

$('#children').hammer().bind('tap', function(e) {
  //Same here
});
person Jay    schedule 13.06.2012
comment
arguments.callee устарел - person chrisfrancis27; 13.06.2012
comment
Я бы предположил, что это только в строгом режиме... developer.mozilla. org/en/JavaScript/Reference/, и я бы не позволил такой мелочи помешать мне выполнить поставленную задачу... используйте это и вернитесь к проблеме, когда закончите. - person Jay; 13.06.2012
comment
Потому что это не дает улучшения производительности... и кого это волнует? stackoverflow.com/questions/3145966/ - person Jay; 13.06.2012
comment
strict для новичков ИМХО, чтобы не облажаться. - person Jay; 13.06.2012
comment
Что ж, разберитесь сами... очевидно, что-то делаете вы или ваша библиотека... У меня нет этой проблемы в моем приложении. - person Jay; 13.06.2012

Вы можете попробовать проверить e.currentTarget (или e.target?) внутри родительского обработчика, чтобы узнать, какой элемент был нажат; если это дочерний элемент, просто немедленно вернитесь, иначе продолжите функцию.

person chrisfrancis27    schedule 13.06.2012
comment
Хорошая идея, но она возвращает родительский элемент, даже если я нажимаю на дочерний элемент. - person TimPetricola; 13.06.2012
comment
Хм. У меня есть подозрение, что Hammer на самом деле привязывается к объекту window, чтобы выполнять все свои вычисления, вычисляя глобальные координаты X/Y события касания, а затем определяя, какой элемент был нажат из этого. В этом случае stopPropagation не будет иметь никакого эффекта. Но я просто предположил, взглянув на исходный код Hammer.js ! - person chrisfrancis27; 13.06.2012