Учебник по Electron.js

Обработка событий

При взаимодействии пользователя с приложением, окном и Web-страницей происходят события. События — это своего рода извещения системы о том, что пользователь выполнил какое-либо действие или внутри самой системы возникло некоторое условие. События возникают при щелчке на элементе, перемещении мыши, нажатии клавиши на клавиатуре, изменении размеров окна, окончании загрузки Web-страницы и т. д.

В предыдущих главах мы уже рассмотрели события объекта приложения, а также события окна. В этой главе мы рассмотрим события, которые генерируется при работе с Web-страницей.

Назначение и удаление обработчиков событий

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

<input type="button" value="Кнопка 1" onclick="handler1()">

При нажатии кнопки будет вызвана функция handler1().

Второй способ подразумевает использование свойств элементов. Причем тут возможны два варианта: с помощью анонимной функции или ссылки на функцию:

document.getElementById('btn2').onclick = function() {
   console.log('Нажата кнопка 2');
};
document.getElementById('btn3').onclick = handler2;

Чтобы получить доступ к свойствам элемента нужно вначале получить ссылку на сам элемент с помощью метода getElementById() объекта document. В качестве значения метод принимает строку с идентификатором элемента. Далее указывается название события, которое совпадает и названием параметра тега. После оператора = задается анонимная функция или ссылка на функцию. Обратите внимание, при указании ссылки название функции указывается без круглых скобок. Если круглые скобки указать, то функция будет вызвана и результат ее работы станет значением свойства.

Первые два способа позволяют назначить только один обработчик. Попытка присвоить другое значение свойству приведет к удалению имеющегося обработчика. Третий способ лишен этого недостатка. Назначить обработчик события позволяет метод addEventListener(). Формат метода:

addEventListener(<Событие>, <Ссылка на функцию>[, <Фаза>]);

В параметре <Событие> указывается название события в виде строки без префикса on, например, click вместо onclick. Ссылка на функцию-обработчик указывается во втором параметре. В эту функцию в качестве параметра передается ссылка на объект event, а внутри функции через ключевое слово this доступна ссылка на текущий элемент. В параметре <Фаза> значение false используется в большинстве случаев. Учитывая, что это значение по умолчанию в Electron, следовательно параметр можно не указывать.

Пример назначения обработчиков различными способами приведен в листинге 7.1.

Листинг 7.1. Назначение обработчиков событий

<!doctype html>
<html lang="ru">
<head>
   <meta charset="utf-8">
   <meta http-equiv="Content-Security-Policy" 
         content="default-src 'self' 'unsafe-inline'">
   <title>Назначение обработчиков событий</title>
</head>
<body>
   <input type="button" value="Кнопка 1" onclick="handler1()">
   <input type="button" value="Кнопка 2" id="btn2">
   <input type="button" value="Кнопка 3" id="btn3">
   <input type="button" value="Кнопка 4" id="btn4">
   <script>
      function handler1() {
         console.log('Нажата кнопка 1');
      }
      function handler2() {
         console.log('Нажата кнопка 3');
      }
      function handler3(e) {
         console.log('Нажата кнопка 4. handler3()');
      }
      function handler4(e) {
         console.log('Нажата кнопка 4. handler4()');
      }
      document.getElementById('btn2').onclick = function() {
         console.log('Нажата кнопка 2');
      };
      // Название функции указывается без круглых скобок
      document.getElementById('btn3').onclick = handler2;
      // Можно назначить сразу несколько обработчиков
      let btn4 = document.getElementById('btn4');
      btn4.addEventListener('click', handler3);
      btn4.addEventListener('click', handler4);
   </script>
</body>
</html>

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

document.getElementById('btn2').onclick = function() {};

Если обработчик назначался через метод addEventListener(), то удалить его можно с помощью метода removeEventListener(). Формат метода:

removeEventListener(<Событие>, <Ссылка на функцию>[, <Фаза>]);

Обратите внимание, нужно обязательно иметь ссылку на обработчик, назначенный с помощью метода addEventListener(). Если при назначении обработчика использовалась анонимная функция, то удалить обработчик будет нельзя. Пример:

document.getElementById('btn4').removeEventListener('click', handler3);

Указатель this

При назначении обработчика с помощью свойства или метода addEventListener() внутри обработчика будет доступна ссылка на текущий элемент через указатель this. С помощью этого указателя можно получить доступ к свойствам элемента. Если обработчик назначается через параметр тега, то указатель нужно передать в качестве параметра. Получим текст на кнопке при ее нажатии (листинг 7.2).

Листинг 7.2. Указатель this

<!doctype html>
<html lang="ru">
<head>
   <meta charset="utf-8">
   <meta http-equiv="Content-Security-Policy"
         content="default-src 'self' 'unsafe-inline'">
   <title>Указатель this</title>
</head>
<body>
   <input type="button" value="Кнопка 1" onclick="handler1(this)">
   <input type="button" value="Кнопка 2" id="btn2">
   <input type="button" value="Кнопка 3" id="btn3">
   <script>
      function handler1(elem) {
         console.log('Нажата кнопка ' + elem.value);
      }
      function handler2(event) {
         console.log('Нажата кнопка ' + this.value);
      }
      document.getElementById('btn2').onclick = function(event) {
         console.log('Нажата кнопка ' + this.value);
      };
      let btn3 = document.getElementById('btn3');
      btn3.addEventListener('click', handler2);
   </script>
</body>
</html>

Объект event

Объект event позволяет получить детальную информацию о произошедшем событии и выполнить необходимые действия. Объект event доступен только в обработчиках событий. При наступлении следующего события все предыдущие значения свойств сбрасываются.

При назначении обработчика с помощью метода addEventListener() или свойства объект event будет доступен через первый параметр. Если обработчик назначается через параметр тега, то объект нужно передать в обработчик в качестве параметра.

Объект event имеет следующие основные свойства:

Благодаря объекту event мы можем назначить один обработчик сразу для нескольких элементов и даже для нескольких типов событий. В листинге 7.3 приведен пример обработки нажатия кнопок внутри одного обработчика.

Листинг 7.3. Объект event

<!doctype html>
<html lang="ru">
<head>
   <meta charset="utf-8">
   <meta http-equiv="Content-Security-Policy"
         content="default-src 'self' 'unsafe-inline'">
   <title>Объект event</title>
</head>
<body>
   <input type="button" value="Кнопка 1" onclick="handler(event)">
   <input type="button" value="Кнопка 2" id="btn2">
   <input type="button" value="Кнопка 3" id="btn3">
   <script>
      function handler(event) {
         console.log(event.type);
         console.log(event.target.value);
         console.log(event.currentTarget.value);
         console.log(event.timeStamp);
      }
      document.getElementById('btn2').onclick = handler;
      let btn3 = document.getElementById('btn3');
      btn3.addEventListener('click', handler);
   </script>
</body>
</html>

Действия по умолчанию

Для многих событий назначены действия по умолчанию, т. е. действия, которые Web-браузер выполняет в ответ на возникшие в документе события. Например, при щелчке на гиперссылке действием по умолчанию будет переход по указанному URL-адресу, нажатие кнопки Отправить приводит к отправке данных формы и т. д.

Иногда действия по умолчанию необходимо прервать. Для этого используются следующие свойства и методы объекта event:

Для отмены действия по умолчанию можно также внутри обработчика вернуть значение false.

В листинге 7.4 приведен пример прерывания перехода по гиперссылке.

Листинг 7.4. Прерывание действий по умолчанию

<!doctype html>
<html lang="ru">
<head>
   <meta charset="utf-8">
   <meta http-equiv="Content-Security-Policy"
         content="default-src 'self' 'unsafe-inline'">
   <title>Прерывание действий по умолчанию</title>
   <script>
      function handler(e) {
         e.preventDefault();
         alert('Перехода по ссылке не будет!');
      }
   </script>
</head>
<body>
   <p>
      <a href="file.html"
         onclick="alert('Перехода по ссылке не будет!'); return false;">
         Нажмите для перехода по ссылке</a><br><br>
      <a href="file.html" onclick="handler(event);">
         Нажмите для перехода по ссылке</a>
   </p>
</body>
</html>

В этом примере рассмотрены два способа прерывания действия по умолчанию. В первой ссылке прерывание действия по умолчанию осуществляется возвратом значения false. Во второй ссылке с помощью свойств и методов объекта объекта event.

Всплывание событий

Что же такое "всплывание" событий? Давайте рассмотрим следующий пример (листинг 7.5).

Листинг 7.5. Всплывание событий

<!doctype html>
<html lang="ru">
<head>
   <meta charset="utf-8">
   <meta http-equiv="Content-Security-Policy"
         content="default-src 'self' 'unsafe-inline'">
   <title>Всплывание событий</title>
   <script>
      function showMsg(msg) {
         let div1 = document.getElementById('div1');
         div1.innerHTML += msg + '<br>';
      }
   </script>
</head>
<body onclick="showMsg('Событие onclick - Документ')">
   <p onclick="showMsg('Событие onclick - Абзац')">
      Щелкните мышью
      <span style="color: red"
            onclick="showMsg('Событие onclick - SPAN')">
         здесь</span>
   </p>
   <div id="div1"></div>
</body>
</html>

В этом примере мы написали обработчики события onclick для трех элементов страницы — тела документа, абзаца и тега <span>. Попробуем щелкнуть левой кнопкой мыши на слове "здесь". В итоге вместо одного события onclick мы получим целую последовательность событий:

Событие onclick - SPAN
Событие onclick - Абзац
Событие onclick - Документ

Иными словами, событие onclick последовательно передается элементу-родителю. Для тега <span> элементом-родителем является абзац. А для абзаца элементом-родителем является само тело документа. Такое прохождение событий называется всплыванием событий.

Управлять всплыванием события позволяют следующие свойства и методы объекта event:

Продемонстрируем прерывание всплывания события на примере (листинг 7.6).

Листинг 7.6. Прерывание всплывания события

<!doctype html>
<html lang="ru">
<head>
   <meta charset="utf-8">
   <meta http-equiv="Content-Security-Policy"
         content="default-src 'self' 'unsafe-inline'">
   <title>Прерывание всплывания события</title>
   <script>
      function showMsg(e, msg) {
         let div1 = document.getElementById('div1');
         div1.innerHTML += msg + '<br>';
         e.stopPropagation();
      }
   </script>
</head>
<body onclick="showMsg(event, 'Событие onclick - Документ')">
   <p onclick="showMsg(event, 'Событие onclick - Абзац')">
      Щелкните мышью
      <span style="color: red"
            onclick="showMsg(event, 'Событие onclick - SPAN')">
         здесь</span>
   </p>
   <div id="div1"></div>
</body>
</html>

Попробуем теперь щелкнуть левой кнопкой мыши на слове "здесь". В итоге вместо трех событий мы получим только одно:

Событие onclick - SPAN

События документа

Перечислим основные события документа:

window.addEventListener('DOMContentLoaded', () => {
   // Здесь назначаем обработчики событий для элементов
});
window.onload = function() {
   // Здесь назначаем обработчики событий для элементов
};

Пример обработки событий документа приведен в листинге 7.7.

Листинг 7.7. События документа

<!doctype html>
<html lang="ru">
<head>
   <meta charset="utf-8">
   <meta http-equiv="Content-Security-Policy"
         content="default-src 'self' 'unsafe-inline'">
   <title>События документа</title>
   <script>
      function showMsg(event, msg) {
         let div1 = document.getElementById('div1');
         div1.innerHTML += msg + '<br>';
         console.log(event);
      }
      window.addEventListener('DOMContentLoaded', (e) => {
         showMsg(e, 'Событие DOMContentLoaded');
      });
   </script>
</head>
<body onload="showMsg(event, 'Событие onload')"
      onscroll="showMsg(event, 'Событие onscroll')"
      onresize="showMsg(event, 'Событие onresize')">
   <div id="div1"></div>
   <div style="height: 600px"></div>
</body>
</html>

События мыши

Перечислим основные события мыши:

События возникают последовательно, например, последовательность событий при нажатии кнопки мыши на элементе страницы будет такой:

onmousedown
onmouseup
onclick

При двойном нажатии последовательность будет такой:

onmousedown
onmouseup
onclick
ondblclick

Это значит, что событие ondblclick возникает после события onclick.

Продемонстрируем обработку событий мыши на примере (листинг 7.8).

Листинг 7.8. События мыши

<!doctype html>
<html lang="ru">
<head>
   <meta charset="utf-8">
   <meta http-equiv="Content-Security-Policy"
         content="default-src 'self' 'unsafe-inline'">
   <title>События мыши</title>
   <script>
      function showMsg(event, msg) {
         let div1 = document.getElementById('div1');
         div1.innerHTML += msg + '<br>';
         console.log(event);
      }
   </script>
</head>
<body onmousedown="showMsg(event, 'Событие onmousedown')"
      onmouseup="showMsg(event, 'Событие onmouseup')"
      onclick="showMsg(event, 'Событие onclick')"
      ondblclick="showMsg(event, 'Событие ondblclick')"
      oncontextmenu="showMsg(event, 'Событие oncontextmenu')"
      onwheel="showMsg(event, 'Событие onwheel')">
   <p onmouseover="showMsg(event, 'Событие onmouseover')"
      onmouseout="showMsg(event, 'Событие onmouseout')">
      Щелкните мышью в любом месте страницы
   </p>
   <div id="div1"></div>
   <div style="height: 600px"></div>
</body>
</html>

Получить информацию о событии позволяют следующие свойства:

События клавиатуры

Перечислим события клавиатуры:

При нажатии клавиши на клавиатуре последовательность будет такой:

onkeydown
onkeypress
onkeyup

Продемонстрируем обработку событий клавиатуры на примере (листинг 7.9).

Листинг 7.9. События клавиатуры

<!doctype html>
<html lang="ru">
<head>
   <meta charset="utf-8">
   <meta http-equiv="Content-Security-Policy"
         content="default-src 'self' 'unsafe-inline'">
   <title>События клавиатуры</title>
   <script>
      function showMsg(event, msg) {
         let div1 = document.getElementById('div1');
         div1.innerHTML += msg + '<br>';
         console.log(event);
      }
   </script>
</head>
<body onkeydown="showMsg(event, 'Событие onkeydown')"
      onkeypress="showMsg(event, 'Событие onkeypress')"
      onkeyup="showMsg(event, 'Событие onkeyup')">
   <p>Нажмите клавишу на клавиатуре</p>
   <div id="div1"></div>
</body>
</html>

Получить информацию о событии позволяют следующие свойства:

События формы

Перечислим основные события формы:

Продемонстрируем обработку событий формы на примере (листинг 7.10).

Листинг 7.10. События формы

<!doctype html>
<html lang="ru">
<head>
   <meta charset="utf-8">
   <meta http-equiv="Content-Security-Policy"
         content="default-src 'self' 'unsafe-inline'">
   <title>События формы</title>
   <script>
      function showMsg(event, msg) {
         let div1 = document.getElementById('div1');
         div1.innerHTML += msg + '<br>';
         console.log(event);
      }
   </script>
</head>
<body>
   <form action="#" method="GET"
      onsubmit="showMsg(event, 'Событие onsubmit'); return false"
      onreset="showMsg(event, 'Событие onreset')">
      <div>
         Логин:<br>
         <input type="text" name="login"
                onfocus="showMsg(event, 'Событие onfocus')"
                onblur="showMsg(event, 'Событие onblur')"
                onchange="showMsg(event, 'Событие onchange')"
                oninput="showMsg(event, 'Событие oninput')"><br>
         E-mail:<br>
         <input type="text" name="email" required
                oninvalid="showMsg(event, 'Событие oninvalid')"><br>
         Описание:<br>
         <textarea name="descr" rows="10" cols="15"></textarea><br>
         <input type="reset" value="Очистить">
         <input type="submit" value="Отправить">
      </div>
   </form>
   <div id="div1"></div>
</body>
</html>