August 18, 2019

Привлечение внимания к окну

Материал на этой странице устарел, поэтому скрыт из оглавления сайта.

Проверить, находится ли окно в фокусе, а также перевести внимание посетителя на него – сложно.

В первую очередь, это потому, что JavaScript не интегрирован с оконным менеджером ОС. Кроме того, браузер охраняет права посетителя: если он хочет скрыть окно, то JavaScript не может его остановить.

Но кое-что сделать, конечно, можно. Об этом и поговорим.

Метод window.focus

Метод window.focus позволяет сфокусироваться на окне. Он работает по-разному в разных ОС и браузерах.

Проверьте, например:

setInterval(function() { window.focus() }, 1000);

Что будет, если запустить этот код, и затем переключиться в другое окно или вкладку?

Можно подумать, что окно будет оказываться в фокусе раз в секунду. Но это не так.

Произойдёт одно из трёх:

  1. Вообще никакого эффекта. Самый распространённый случай, если в окне много вкладок.
  2. Окно развернётся (при необходимости) и выйдет на передний план. Обычно это происходит, когда метод window.focus() вызывается для попапа, а активно сейчас – главное окно. То есть, в этом случае вызов сработает.
  3. Заголовок окна начнёт мигать. Чтобы увидеть это в действии – откройте данную страницу в IE, запустите код и переключитесь на другое окно. Браузер попытается привлечь Ваше внимание миганием/мерцанием заголовка окна.

Мерцание заголовка

В дополнение к window.focus() используют мерцание заголовка окна, как показано в примере ниже:

<script>
  var win = open('/', 'test', 'width=300,height=300')

  function getAttention(win) {
    if (win.closed) {
      alert( "Окно закрыто, привлечь внимание к нему нельзя" );
      return;
    }

    win.focus();
    var i = 0;
    var show = ['************', win.document.title];

    var focusTimer = setInterval(function() {
      if (win.closed) {
        clearInterval(focusTimer);
        return;
      }
      win.document.title = show[i++ % 2];
    }, 1000);

    win.document.onmousemove = function() {
      clearInterval(focusTimer);
      win.document.title = show[1];
      win.document.onmousemove = null;
    }
  }
</script>

<input type="button" onclick="getAttention(win)" value="getAttention(win)">

Запустите код и сверните всплывающее окно. А затем – нажмите кнопку с надписью «getAttention(win)». Браузер будет привлекать ваше внимание, как умеет ;)

Обратите внимание: в коде есть проверка на win.closed. Попытка манипулирования закрытым окном вызовет исключение.

Как только посетитель сфокусировался на окне индикация прекращается. Для определения момента фокусировки в примере выше используется событие document.onmousemove.

Можно было использовать событие window.onfocus, но, оказывается, оно ненадёжно.

Событие window.onfocus

Вот переписанный вариант функции getAttention(win), с использованием события onfocus:

<script>
  var win = open('/', 'test', 'width=300,height=300')

  function getAttention(win) {
    if (win.closed) {
      alert( "Окно закрыто, привлечь внимание к нему нельзя" );
      return;
    }

    var i = 0;
    var show = ['************', win.document.title];

    function stop() {
      clearInterval(focusTimer);
      win.document.title = show[1];
    }

    win.onfocus = function() {
      stop();
      win.onfocus = null;
    }

    var focusTimer = setInterval(function() {
      if (win.closed) {
        clearInterval(focusTimer);
        return;
      }

      win.document.title = show[i++ % 2];
    }, 1000);

    win.focus();
  }
</script>

<input type="button" onclick="getAttention(win)" value="getAttention(win)">

Далее мы посмотрим случаи, когда он не срабатывает, и почему нам всё же нужно document.onmousemove.

Когда событие onfocus не работает?

Возможно такое, что посетитель переключается на окно, а window.onfocus не происходит.

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

Попробуйте проделать следующее:

  1. Запустите пример с getAttention в Chrome или IE (кстати, в них нельзя отключить адресную панель).
  2. Поместите курсор в панель адреса всплывающего окна.
  3. Перейдите обратно к главному окну и нажмите кнопку getAttention(win)

Вы увидите, что несмотря на то, что вы переключились на окно, и оно сейчас на переднем плане, событие onfocus не срабатывает.

Есть и другие случаи, когда переключение между окнами не вызывает window.onfocus. Скажем, если окно сфокусировать щелчком в поле ввода формы, то в IE события window.onfocus (а также window.onfocusin) – не сработают!

Можно попробовать поймать момент фокусировки и по-другому, повесив дополнительные обработчики событий на document. В главе Фокусировка: focus/blur описана техника делегирования для focus/blur.

Но этот способ получает фокус только если посетитель сфокусируется где-то в документе: щёлкнет или сделает ещё какое-то действие в документе, а не просто посмотрит на него и проведёт над ним мышкой.

Впрочем, никто не мешает использовать сочетание всех описанных методов.

Итого

Фокусировка и привлечение внимания к окну:

  • Метод focus для window не надёжен. Окнами и вкладками браузера можно уверенно управлять только на уровне ОС.

    Поэтому для привлечения внимания посетителя к окну стоит также использовать мерцающий заголовок окна.

Обнаружение переключения на окно:

  • У window есть событие onfocus, но оно также ненадёжно.

    Поэтому для определения переключения на окно – используйте его вместе с делегируемым focus на документе, а также document.onmousemove.

Карта учебника

Комментарии

перед тем как писать…
  • Если вам кажется, что в статье что-то не так - вместо комментария напишите на GitHub.
  • Для одной строки кода используйте тег <code>, для нескольких строк кода — тег <pre>, если больше 10 строк — ссылку на песочницу (plnkr, JSBin, codepen…)
  • Если что-то непонятно в статье — пишите, что именно и с какого места.