Управление фокусировкой

Рассмотренные на предыдущем занятии элементы формы:

input, textarea, select

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

<!DOCTYPE html>
<html>
<head>
<title>Уроки по JavaScript</title>
</head>
<body>
<form name="reg">
<p><input name="user" value="" />
<p><input name="sex" type="radio" checked />М 
<input name="sex" type="radio" />Ж
<p>Город: <select name="city">
<option>Москва</option>
<option>Санкт-Петербург</option>
<option>Тверь</option>
</select>
<p>Согласие <input name="agree" type="checkbox" />
<p><textarea name="about" rows="10" cols="30">О себе</textarea>
<p><input type="submit" name="submit">
</form>
<script>
</script>
</body>
</html>

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

  • focus – при получении фокуса;
  • blur – при потере фокуса.

Давайте в этом убедимся. Повесим на первый элемент ввода обработчики этих двух событий:

let frm = document.forms[0];
frm.user.onfocus = function(event) {
    console.log("получение фокуса");
};
 
frm.user.onblur = function(event) {
    console.log("потеря фокуса");
};

Теперь, щелкая по элементу, появится сообщение «получение фокуса», то есть, сработало событие focus. А при переходе к другому элементу появляется событие «потеря фокуса», то есть, сработало событие blur.

Когда могут понадобиться такие события? Например, для проверки корректности ввода данных в поле ввода. Для простоты положим, что имя пользователя не должно содержать символа #. Такую проверку можно сделать так:

frm.user.onblur = function(event) {
      if(frm.user.value.includes('#'))
               frm.user.classList.add('error');
      else frm.user.classList.remove('error');
};

То есть, когда в поле ввода содержится символ #, то оно принимает красный фон. Соответственно стиль можно прописать так:

<style>
.error { background: #CC0000; }
</style>

А в обработчике фокуса будем удалять этот класс, то есть, убирать красный фон:

frm.user.classList.remove('error');

Однако, обратите внимание, стандарты HTML 5 и выше позволяют в полях ввода прописывать атрибуты

required, pattern

для автоматической проверки корректности введенных данных. Так что скрипт следует использовать, только если недостаточно встроенных способов валидации данных.

Также следует иметь в виду, что события focus и blur не всплывают, то есть, мы не можем перехватить их обработчиком элемента более высокого уровня в иерархии DOM-дерева. Например, если поставить обработчик onfocus на форму:

frm.onfocus = function() {
     console.log("form: focus");
}

то он никогда не будет срабатывать. Однако, тут есть один нюанс: события focus и blur хоть и не всплывают, но зато имеют фазу погружения и мы можем их перехватить на форме в этот момент:

frm.addEventListener("focus", function() {
         console.log("form: focus");
}, true);

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

focusin и focusout

которые работают также как и focus и blur, но всплывают. Обработчики этих событий можно добавлять только через метод addEventListener, следующим образом:

frm.addEventListener("focusin", function() {
            console.log("form: focusin");
});

Теперь событие успешно перехватывается на этапе всплытия.

В JavaScript существуют методы:

  • elem.focus() – для установки фокуса на элемент;
  • elem.blur() – для снятия фокуса с элемента.

Например, так:

frm.about.focus();

и при обновлении документа мы увидим фокусировку на теге textarea. Аналогично работает второй метод. Но здесь есть несколько тонких моментов. Во-первых, эти методы могут не работать в браузерах Firefox. Во-вторых, бывают случаи, когда фокусировка с элемента будет сниматься автоматически. Например, при появлении модальных окон, вызванных методами:

alert(), prompt(), confirm()

Так что полагаться целиком на методы focus и blur не стоит и в практике программирования ими стараются не пользоваться. Вместо этого лучше полагаться на события focus и blur и реализовывать логику через их обработчики. Или же, используя псевдокласс :focus, определять стили сфокусированного элемента.

Работая с событиями focus и blur, следует иметь в виду, что далеко не все элементы HTML-документа по умолчанию поддерживают фокусировку. Например, элементы:

div, p, table, span, img и т.п.

Добавим div на нашу страницу:

<div id="block" style="height:50px; background: #777"></div>

И пропишем для него два обработчика:

block.onfocus = function(event) {
      console.log("focus");
}; 
 
block.onblur = function(event) {
      console.log("blur");
};

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

tabindex="1"

Теперь, при щелчке мыши по блоку div, будут срабатывать эти два события. Что это за атрибут tabindex? Он указывает в какой последовательности следует переключать фокусы между элементами, при нажатии на клавишу Tab. Так что, если мы какой-то элемент включаем в эту последовательность, то он должен обладать фокусировкой. И браузеры ее включают, даже если, ранее элемент не обладал таким свойством. Причем, это свойство можно установить и непосредственно в скрипте, используя свойство tabIndex:

block.tabIndex = 1;

Обратите внимание на его написание: здесь буква I заглавная.

У этого атрибута (или же свойства) есть два специальных значения:

  • tabindex="0" располагает элемент на уровне с другими элементами без атрибута tabindex, но обладающих фокусировкой;
  • tabindex="-1" позволяет фокусироваться на элементе только программно.

Ну и, наконец, последнее. Для получения текущего элемента с фокусировкой, используется свойство:

let active = document.activeElement;
console.log(active);

И в консоли мы увидим элемент textarea, который имеет фокус на странице.

Видео по теме