Използване на 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
Публикувах отговор на свързания въпрос Има ли „има фокус“ ​​в 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 );
};

Цитирано от Mathias Bynens тук:

Обърнете внимание, че тестът (elem.type || elem.href) беше добавен за филтриране на фалшиви положителни резултати като тяло. По този начин гарантираме, че филтрираме всички елементи с изключение на контролите на формуляра и хипервръзките.

Вие определяте нов селектор. Вижте Добавки/Авторство. След това можете да направите:

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 - Благодаря за актуализацията (между другото можете да редактирате този wiki отговор на общността!) - 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
FYI, ако използвате karma, трябва първо да добавите елемента към тялото във вашия тест. Вижте 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's hover. Предоставяте две функции, една за влизане на мишката и една за излизане на мишката. - person bloudermilk; 09.06.2009

Проследявайте и двете състояния (задържан, фокусиран) като флагове true/false и всеки път, когато едното се промени, стартирайте функция, която премахва границата, ако и двете са false, в противен случай показва граница.

И така: onfocus задава фокусирано = true, onblur задава фокусирано = false. onmouseover sets hovered = true, onmouseout sets 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
защо да използвате плъгин, когато можете просто да използвате core jquery? - person Marcy Sutton; 16.12.2011
comment
Ти си прав. Но не знаех решение за този проблем преди 2 години. - person Murat Çorlu; 18.12.2011

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

$(formObj).select();

Поради странности между различните браузъри изборът понякога ще бъде заменен от щракването, което го е причинило, и ще премахне избора на съдържанието веднага след това в полза на поставянето на курсора в текстовото поле (работи предимно добре в FF, но не успя в IE)

Мислех, че мога да разреша това, като сложа леко забавяне на избрания...

setTimeout(function(){$(formObj).select();},200);

Това работеше добре и изборът щеше да продължи, но възникна забавен проблем.. Ако преминете от едно поле към следващото, фокусът ще превключи към следващото поле, преди да се осъществи изборът. Тъй като избраното открадва фокуса, фокусът ще се върне обратно и ще задейства ново събитие „фокус“. Това завърши в каскада от избори на вход, танцуващи по целия екран.

Работещо решение би било да се провери дали полето все още има фокус, преди да се изпълни 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