JQuery: огонь click () перед событием blur ()

134

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

<input type="text" id="myinput">
<div id="myresults"></div>

На входном blur()событии я хочу скрыть результаты div:

$("#myinput").live('blur',function(){
     $("#myresults").hide();
});

Когда я что-то записываю в свой ввод, я отправляю запрос на сервер и получаю ответ json, разбираю его в структуре ul-> li и помещаю этот ul в мой #myresultsdiv.

Когда я нажимаю на этот разобранный элемент li, я хочу установить значение от li до input и скрыть #myresultsdiv

$("#myresults ul li").live('click',function(){
     $("#myinput").val($(this).html());
     $("#myresults").hide();
});

Все идет хорошо, но когда я нажимаю на blur()событие li, которое запускается раньше, click()и значение input не получает html li.

Как я могу настроить click()событие раньше blur()?

Егор Сазанович
источник
В таком случае, почему вы используете функцию размытия? когда ваша потребность уже заполнена от функции щелчка.
Оваис Икбал
Это, вероятно, не изменит порядок запуска ваших событий, но если blurон действительно запускается после того, как вы нажали на li, то вам, вероятно, не нужно выполнять $("#myresults").hide()обработчик щелчка. Кажется, что происходит то, что $(this).html()возвращается пустая строка. Не могли бы вы logили alert $(this).html()убедиться?
veeTrain
@OwaisIqbal иногда нет результатов, иногда пользователь не хочет ничего выбирать из предложений, иногда пользователь больше не хочет использовать этот ввод, но я должен скрыть неиспользованный результат
Егор Сазанович
@veeTrain, в моих обработчиках много действий, я просто свел их к минимуму, чтобы было проще понять проблему в моем вопросе. ps Я пытался добавить точку наблюдения в firebug on blur()и handlers click(), после blur()конца никаких действий нет
Егор Сазанович
Похоже, вам нужно поставить в очередь функции. Попробуйте взглянуть на эту страницу: stackoverflow.com/questions/1058158/… . Часть «первым пришел - первым обслужен» (FIFO) может принадлежать вам
Patriotec

Ответы:

312

Решение 1

Слушать mousedownвместоclick .

События mousedownи blurпроисходят один за другим при нажатии кнопки мыши, ноclick происходят только после отпускания.

Решение 2

Вы можете preventDefault()в mousedownблокировать ниспадающее меню от кражи фокуса. Небольшое преимущество заключается в том, что значение будет выбрано, когда кнопка мыши отпущена, именно так работают нативные компоненты выбора.JSFiddle

$('input').on('focus', function() {
    $('ul').show();
}).on('blur', function() {
    $('ul').hide();
});

$('ul').on('mousedown', function(event) {
    event.preventDefault();
}).on('click', 'li', function() {
    $('input').val(this.textContent).blur();
});
Алексей Лебедев
источник
12
Решение 1 сработало для меня в этой же ситуации! Легкая смена! Спасибо :)
Джон
Спасибо :) Но можете ли вы объяснить, почему прослушивание mousedown вместо щелчка работает как очарование?
Мудассир Али
3
@MudassirAli, потому что событие mousedown происходит до размытия, а щелчок - после. jsfiddle.net/f3BKP
Алексей Лебедев
Решение № 1, на мой взгляд, лучший выбор. Просто и эффективно. Тайм-аут будет означать больше кода + больше места для непредвиденного поведения (сколько времени ожидания? Достаточно долго, чтобы зарегистрировать щелчок, но не слишком долго, чтобы запутать использование ...).
cw24
5
Решение № 2 гениально. Я бы никогда этого не понял! Спасибо
Тобиа
2
$(document).on('blur', "#myinput", hideResult);

$(document).on('mousedown', "#myresults ul li", function(){
     $(document).off('blur', "#myinput", hideResult); //unbind the handler before updating value
     $("#myinput").val($(this).html()).blur(); //make sure it does not have focus anymore
     hideResult(); 
     $(document).on('blur', "#myinput", hideResult);  //rebind the handler if needed
});

function hideResult() {
     $("#myresults").hide();
}

FIDDLE

adeneo
источник
2

Я столкнулся с этой проблемой, и использование mousedownне вариант для меня.

Я решил это с помощью setTimeoutфункции обработчика

        elem1.on('blur',function(e) {

            var obj = $(this);

            // Delay to allow click to execute
            setTimeout(function () {
                if (e.type == 'blur') {

                  // Do stuff here

                }
            }, 250);
        });

        elem2.click( function() {
            console.log('Clicked');
        });
geckob
источник
2

Я только что ответил на аналогичный вопрос: https://stackoverflow.com/a/46676463/227578

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

$("#myinput").live('blur',function(e){
     if (!e.relatedTarget || !$(e.relatedTarget).is("#myresults ul li")) {
         $("#myresults").hide();
     }
});
Dule
источник
в моем случае event.relatedTarget возвращает ноль, есть идеи, почему это может быть?
gaurav5430
хорошо, получил ответ здесь: stackoverflow.com/questions/42764494/…
gaurav5430
0

Mousedown solutions не работает для меня, когда я нажимаю на не кнопочные элементы. Итак, вот что я сделал с функцией размытия в моем коде:

.on("blur",":text,:checkbox,:radio,select",function() {
/*
* el.container 
* container, you want detect click function on.
*/
            var outerDir = el.container.find(':hover').last();
            if (outerDir.length) {
                if ($.inArray(outerDir.prop('tagName'), ["A","SELECT"] ) != -1 || outerDir.prop('type') == 'button' || outerDir.prop('type') == 'submit') {
                    outerDir.click();
                }
                if (outerDir.prop('type') == 'checkbox') {
                    outerDir.change();
                }
                return false;
            }
/*          
* YOUR_BLUR_FUNCTION_HERE;
*/
});
Андрей
источник