Использование jQuery для проверки фокусировки ввода

На первой странице сайта, который я создаю, несколько <div> используют псевдокласс CSS :hover для добавления границы, когда на них наводится указатель мыши. Один из <div>s содержит <form>, который, используя jQuery, сохранит границу, если вход внутри него имеет фокус. Это работает отлично, за исключением того, что IE6 не поддерживает :hover ни для каких элементов, кроме <a>s. Итак, только для этого браузера мы используем jQuery для имитации CSS :hover с помощью метода $(#element).hover(). Единственная проблема заключается в том, что теперь, когда jQuery обрабатывает как форму focus() , так и hover(), когда ввод имеет фокус, пользователь перемещает мышь внутрь и наружу, граница исчезает.

Я думал, что мы могли бы использовать какое-то условие, чтобы остановить такое поведение. Например, если бы мы проверили при отключении мыши, есть ли у какого-либо из входов фокус, мы могли бы остановить исчезновение границы. AFAIK, в jQuery нет селектора :focus, поэтому я не уверен, как это сделать. Любые идеи?


person bloudermilk    schedule 08.06.2009    source источник
comment
Вы можете попытаться свести это к нескольким предложениям о том, что требуется, и о том, что у меня происходит?   -  person mkoryak    schedule 09.06.2009
comment
Я думаю, вам нужно изучить захват событий фокуса и размытия (docs.jquery.com/Events/focus и docs.jquery.com/Events/blur)   -  person Wolfr    schedule 09.06.2009
comment
Я отправил ответ на связанный вопрос Есть ли a 'имеет фокус' в JavaScript (или jQuery)?. Я улучшил [подход cletus, процитировано gnarf] (# 2684561).   -  person luistamawong    schedule 13.08.2010


Ответы (15)


jQuery 1.6+

jQuery добавил селектор :focus, поэтому нам больше не нужно добавлять его самостоятельно. Просто используйте $("..").is(":focus")

jQuery 1.5 и ниже

Изменить: Время меняется, и мы находим более эффективные методы для проверки фокуса, новым фаворитом является эта суть от Бена Алмана:

jQuery.expr[':'].focus = function( elem ) {
  return elem === document.activeElement && ( elem.type || elem.href );
};

Цитата из Матиаса Биненса, здесь:

Обратите внимание, что тест (elem.type || elem.href) был добавлен для фильтрации ложных срабатываний, таких как body. Таким образом, мы отфильтровываем все элементы, кроме элементов управления формой и гиперссылок.

Вы определяете новый селектор. См. Плагины / Разработка. Тогда вы сможете:

if ($("...").is(":focus")) {
  ...
}

or:

$("input:focus").doStuff();

Любой jQuery

Если вы просто хотите выяснить, какой элемент имеет фокус, вы можете использовать

$(document.activeElement)

Если вы не уверены, будет ли версия 1.6 или ниже, вы можете добавить селектор :focus, если он отсутствует:

(function ( $ ) {
    var filters = $.expr[":"];
    if ( !filters.focus ) { 
        filters.focus = function( elem ) {
           return elem === document.activeElement && ( elem.type || elem.href );
        };
    }
})( jQuery );
person Community    schedule 21.04.2010
comment
Это может вызвать ложные срабатывания. См. stackoverflow.com/questions/967096/ для получения дополнительной информации (спасибо Бену Альману и Диего Перини). - person Mathias Bynens; 22.03.2011
comment
@Mathias Bynens - Спасибо за обновление (кстати, вы можете редактировать этот ответ вики сообщества!) - person gnarf; 23.03.2011
comment
А что если вам нужно, чтобы он работал и с 1.5-, и с 1.6? Я не хочу переопределять собственный селектор фокуса jQuery. Что-то вроде if (!jQuery.expr[':'].focus) { /* gist from Ben Alman */ }? - person Betamos; 03.06.2011
comment
@betamos - Совершенно верно ... Я добавлю что-нибудь в ответ, чтобы отразить это. - person gnarf; 04.06.2011
comment
@Alex - Пожалуйста, предоставьте сокращенный тестовый пример для jsFiddle, показывающий проблему, потому что, насколько я могу судить, нет причин, по которым этот не должен работать с динамическими элементами. Я называю махинации ... - person gnarf; 15.06.2012
comment
Я мог ошибаться, но это не сработало для меня, и я просто хотел поделиться ... Мне придется провести еще несколько тестов, чтобы убедиться, что это не только я ... - person Alex; 15.06.2012
comment
Также можно избежать использования сфокусированного элемента в селекторе, например: $('[placeholder]:not(:focus)') - person jocull; 13.02.2013
comment
К вашему сведению, если вы используете карму, вам нужно сначала добавить элемент в тело в вашем тесте. См. stackoverflow.com/questions/19994424/ - person rouan; 21.05.2014

CSS:

.focus {
    border-color:red;
}

JQuery:

  $(document).ready(function() {

    $('input').blur(function() {
        $('input').removeClass("focus");
      })
      .focus(function() {
        $(this).addClass("focus")
      });
  });
person Daniel Moura    schedule 08.06.2009

Вот более надежный ответ, чем принятый в настоящее время:

jQuery.expr[':'].focus = function(elem) {
  return elem === document.activeElement && (elem.type || elem.href);
};

Обратите внимание, что тест (elem.type || elem.href) был добавлен для фильтрации ложных срабатываний, таких как body. Таким образом, мы отфильтровываем все элементы, кроме элементов управления формой и гиперссылок.

(Взято из этой сути Бен Алман.)

person Mathias Bynens    schedule 22.03.2011

Обновление за апрель 2015 г.

Поскольку этот вопрос существует некоторое время и в игру вступили некоторые новые соглашения, я считаю, что должен упомянуть, что метод .live обесценился.

Вместо него был введен метод .on.

Их документация весьма полезна для объяснения того, как это работает;

Метод .on () присоединяет обработчики событий к текущему выбранному набору элементов в объекте jQuery. Начиная с jQuery 1.7, метод .on () предоставляет все функции, необходимые для подключения обработчиков событий. Для получения помощи в преобразовании из более старых методов событий jQuery см. .Bind (), .delegate () и .live ().

Итак, чтобы настроить таргетинг на событие, ориентированное на ввод, вы можете использовать это в сценарии. Что-то вроде:

$('input').on("focus", function(){
   //do some stuff
});

Это довольно надежно и даже позволяет вам использовать клавишу TAB.

person jbutler483    schedule 07.04.2015
comment
очень хорошее решение, спасибо. Используйте on("focusout", для противоположной функции - person Barbz_YHOOL; 20.08.2020

Я не совсем уверен, что вам нужно, но похоже, что этого можно достичь, сохранив состояние входных элементов (или div?) В качестве переменной:

$('div').each(function(){

    var childInputHasFocus = false;

    $(this).hover(function(){
        if (childInputHasFocus) {
            // do something
        } else { }
    }, function() {
        if (childInputHasFocus) {
            // do something
        } else { }
    });

    $('input', this)
        .focus(function(){
            childInputHasFocus = true;
        })
        .blur(function(){
            childInputHasFocus = false;
        });
});
person James    schedule 08.06.2009
comment
Это то, чем я закончил, но я использовал произвольный класс CSS, а не глобальную переменную javascript. - person bloudermilk; 09.06.2009
comment
Я использовал его вариант. Новый плагин jQuery не требуется. Это делает меня счастливым туристом! - person Dennis Day; 09.11.2010

Альтернативой использованию классов для отметки состояния элемента является внутренняя функциональность хранилища данных .

P.S .: Вы можете хранить логические значения и все, что захотите, используя функцию data(). Дело не только в струнах :)

$("...").mouseover(function ()
{
    // store state on element
}).mouseout(function ()
{
    // remove stored state on element
});

И тогда это просто вопрос доступа к состоянию элементов.

person cllpse    schedule 09.06.2009

если кому-то интересно, есть способ лучше сфокусироваться, $(foo).focus(...)

http://api.jquery.com/focus/

person CrackSmoker9000    schedule 30.10.2014

Вы думали об использовании mouseOver и mouseOut для имитации этого. Также посмотрите mouseEnter и mouseLeave

person mkoryak    schedule 08.06.2009
comment
По сути, это то, что я делаю с зависанием jQuery. Вы предоставляете две функции: одну для ввода мыши и одну для вывода мыши. - person bloudermilk; 09.06.2009

Следите за обоими состояниями (при наведении курсора, в фокусе) как за истинными / ложными флагами, и всякий раз, когда одно из них изменяется, запускайте функцию, которая удаляет границу, если оба значения ложны, иначе показывает границу.

Итак: onfocus устанавливает focus = true, onblur устанавливает focus = false. onmouseover устанавливает hovered = true, onmouseout устанавливает hovered = false. После каждого из этих событий запускаем функцию, которая добавляет / удаляет границу.

person Blixt    schedule 08.06.2009

Насколько я знаю, вы не можете спрашивать браузер, есть ли у какого-либо ввода на экране фокус, вам нужно настроить какое-то отслеживание фокуса.

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

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

После его создания вы можете проверить noFocus перед заменой границ.

person Ryan Florence    schedule 08.06.2009

Нет: focus, но есть: selected http://docs.jquery.com/Selectors/selected

но если вы хотите изменить внешний вид вещей в зависимости от того, что выбрано, вам, вероятно, следует работать с событиями размытия.

http://docs.jquery.com/Events/blur

person Chris Brandsma    schedule 08.06.2009

Существует плагин для проверки фокусировки элемента: http://plugins.jquery.com/project/focused

$('input').each(function(){
   if ($(this) == $.focused()) {
      $(this).addClass('focused');
   }
})
person Murat Çorlu    schedule 12.11.2009
comment
зачем использовать плагин, если можно просто использовать основной jquery? - person Marcy Sutton; 16.12.2011
comment
Ты прав. Но 2 года назад я не знал решения этой проблемы. - person Murat Çorlu; 18.12.2011

У меня было событие .live ("focus"), настроенное на select () (выделение) содержимого ввода текста, чтобы пользователю не приходилось выбирать его перед вводом нового значения.

$ (formObj) .select ();

Из-за причуд между разными браузерами выбор иногда заменялся щелчком, вызвавшим его, и сразу после этого он отменял выбор содержимого в пользу размещения курсора в текстовом поле (в основном работал нормально в FF, но не работал в IE)

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

setTimeout (функция () {$ (formObj) .select ();}, 200);

Это работало нормально, и выбор сохранялся, но возникла забавная проблема ... Если вы переходили от одного поля к другому, фокус переключался на следующее поле до того, как произошло выбор. Поскольку select крадет фокус, тогда фокус вернется и вызовет новое событие «focus». Это закончилось каскадом входных выборок, танцующих по всему экрану.

Работоспособным решением было бы проверить, что поле все еще находится в фокусе перед выполнением select (), но, как уже упоминалось, нет простого способа проверить ... Я закончил тем, что просто отказался от всего автоматического выделения, а не поворачивал то, что должно быть единственный вызов jQuery select () в огромную функцию, загруженную подпрограммами ...

person Brian    schedule 08.09.2011

В итоге я создал произвольный класс с именем .elementhasfocus, который добавляется и удаляется в функции jQuery focus (). Когда функция hover () запускается при отключении мыши, она проверяет наличие .elementhasfocus:

if(!$("#quotebox").is(".boxhasfocus")) $(this).removeClass("box_border");

Поэтому, если у него нет этого класса (читай: ни у одного элемента в div нет фокуса), граница удаляется. В противном случае ничего не происходит.

person bloudermilk    schedule 08.06.2009

Простой

 <input type="text" /> 



 <script>
     $("input").focusin(function() {

    alert("I am in Focus");

     });
 </script>
person Code Spy    schedule 16.03.2012
comment
Это не говорит вам, какой элемент в данный момент находится в фокусе. Он вызывается, когда фокус получает новый элемент. Поэтому, если элемент уже имеет фокус, и вы хотите знать, является ли он одним, этот код бесполезен. - person Alexis Wilke; 01.02.2014