it-swarm.com.ru

Как мне обработать щелчок в любом месте страницы, даже когда определенный элемент останавливает распространение?

Мы работаем над инструментом JavaScript, в котором есть более старый код, , Поэтому мы не можем переписать весь инструмент.

Теперь в меню было добавлено положение, закрепленное внизу, и клиенту очень хотелось бы, чтобы у него была кнопка переключения для открытия и закрытия меню, За исключением того, что закрытие должно происходить автоматически, когда пользователь начинает делать что-то вне меню, например, когда пользователь возвращается на страницу и выбирает что-то или нажимает на поле формы.

Технически это может работать с событием click в body, вызывая при любом щелчке, Однако в старом коде есть множество элементов, где событие click обрабатывалось по внутренней ссылке, и return false был добавлен в функцию click, чтобы сайт не переходил к тегу href ссылки.

Очевидно, что такая общая функция работает, но не при нажатии на внутреннюю ссылку, где возвращаемое значение false останавливает распространение.

$('body').click(function(){
  console.log('clicked');
});

Есть ли способ, которым я могу в любом случае принудительно вызвать событие щелчка тела, Или есть другой способ, которым я могу позволить меню исчезнуть, используя какое-то глобальное событие щелчка или что-то подобное?

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

32
Sander

События в современных реализациях DOM имеют две фазы: capturing и bubbling. Фаза захвата - это первая фаза, текущая от defaultView документа к цели события, за которой следует фаза пузырьков, которая течет от цели события обратно к defaultView. Для получения дополнительной информации см. http://www.w3.org/TR/DOM-Level-3-Events/#event-flow .

Для обработки фазы захвата события вам нужно установить третий аргумент для addEventListener в true:

document.body.addEventListener('click', fn, true); 

К сожалению, как отметил Уэсли, этап захвата события не может быть надежно или вообще невозможен в старых браузерах.

Одним из возможных решений является обработка события mouseup, поскольку порядок событий для кликов:

  1. mouseDown
  2. mouseUp
  3. щелчок

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

55
Andy E

В сотрудничестве с Andy E это темная сторона силы:

var _old = jQuery.Event.prototype.stopPropagation;

jQuery.Event.prototype.stopPropagation = function() {
    this.target.nodeName !== 'SPAN' && _old.apply( this, arguments );
};     

Пример: http://jsfiddle.net/M4teA/2/

Помните, что если все события были связаны с помощью jQuery, вы можете обработать эти случаи только здесь. В этом примере мы просто вызываем исходную функцию .stopPropagation(), если мы не имеем дело с <span>.


Вы не можете предотвратить, нет.

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

$( document.body ).click(function() {
    alert('Hi I am bound to the body!');
});

$( '#bar' ).click(function(e) {
    alert('I am the span and I do prevent propagation');
    e.stopPropagation();
});

$( '#yay' ).click(function() {
    $('span').each(function(i, elem) {
        var events        = jQuery._data(elem).events,
            oldHandler    = [ ],
            $elem         = $( elem );

        if( 'click' in events ) {                        
            [].forEach.call( events.click, function( click ) {
                oldHandler.Push( click.handler );
            });

            $elem.off( 'click' );
        }

        if( oldHandler.length ) {
            oldHandler.forEach(function( handler ) {
                $elem.bind( 'click', (function( h ) {
                    return function() {
                        h.apply( this, [{stopPropagation: $.noop}] );
                    };
                }( handler )));
            });
        }
    });

    this.disabled = 1;
    return false;
});

Пример: http://jsfiddle.net/M4teA/

Обратите внимание, что приведенный выше код будет работать только с jQuery 1.7. Если эти события щелчка были связаны с более ранней версией jQuery или «встроенным», вы все равно можете использовать код, но вам потребуется другой доступ к «старому обработчику».

Я знаю, что я предполагаю, что здесь много сценариев «идеального мира», например, что эти дескрипторы явно вызывают .stopPropagation() вместо возврата false. Таким образом, это все еще может быть бесполезный академический пример, но я чувствовал, что должен его опубликовать :-)

edit: эй, return false; будет работать нормально, к объектам событий обращаются аналогичным образом.

6
jAndy

Если вы убедитесь, что это обработчик событий first , что-то вроде этого может помочь:

$('*').click(function(event) {
    if (this === event.target) { // only fire this handler on the original element
        alert('clicked');
    }
});

Обратите внимание, что если на вашей странице много элементов, это будет действительно очень медленно и не будет работать для чего-либо, добавленного динамически.

3
lonesomeday

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

http://www.quirksmode.org/js/events_order.html

Смежные вопросы:

2
Wesley Petrowski

Вы можете использовать jQuery для добавления прослушивателя событий в DOM документа.

    $(document).on("click", function () {
        console.log('clicked');
    });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

1
Ryan

Я думаю, что это то, что вам нужно:

$("body").trigger("click");

Это позволит вам вызвать событие щелчка мышью из любого места.

0
James Johnson

this является ключом (против evt.target). Смотрите пример.

document.body.addEventListener("click", function (evt) {
    console.dir(this);
    //note evt.target can be a nested element, not the body element, resulting in misfires
    console.log(evt.target);
    alert("body clicked");
});
<h4>This is a heading.</h4>
<p>this is a paragraph.</p>

0
Ron Royston