Таймер. События.

Таймер.

Выполняет функцию через указанный промежуток времени (задержка).

Синтаксис.

setTimeout(функция/код, задержка, аргумент1, аргумент2, ...)

Задержка устанавливается в милисикундах.

Функция setTimeout возвращает идентификатор установленного таймера. Его можно использовать для того, чтобы отменить срабатывание таймера.

Пример.

function HelloWorld(){
    alert("Hello world!");
}
setTimeout(HelloWorld, 1000);

С аргументами.

function Sum(a,b){
    alert(a+b);
}
setTimeout(Sum, 1000,1,2);

Отмена таймера.

clearTimeout(идентификатор_таймера)

Пример.

var id = setTimeout(function(){
    alert("Boom!")},50000
);

clearTimeout(id);

Интервалы.

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

Синтаксис

setInterval(функция/код, интервал_времени, аргумент1,
аргумент2, ...)

Пример.

setInterval(
    function(){
        alert("Boom!");
    },
2000);

В этом коде мы не вызвали clearInterval поэтому окно сообщения с надписью Boom будет вызываться каждые две секунды, пока окно или вкладка браузера не будет закрыта.

Пример с clearInterval

var id = setInterval(IntervalFunc,2000);
var counter = 0;
function IntervalFunc(){
    if(counter == 3){
            clearInterval(id);
            return;
    }
    counter++;
    alert("Boom");
}

Альтернативой использованию setInterval является рекурсивный вызов setTimer.

var id = setTimeout(TimeOutFunc, 2000);
var counter = 0;
function TimeOutFunc() {
    // если таймер сработал уже трижды
    // останавливаем процесс
    if (counter == 3) {
        clearTimeout(id);
        return;
    }
    counter++;
    alert("Boom Timer");

    // ставим занова таймер на две секунды
    id = setTimeout(TimeOutFunc, 2000);
}

Хотя функция «setInterval» кажется более привлекательной для создания таймера — периодического запу- ска определенной функции, она имеет ряд недостатков.

Во-первых, она устанавливает время только между началами запуска функции. Например, если функция сама-по-себе выполняется 0,4 секунды, и мы указали интервал запуска 1 секунду, то пауза между остановкой предыдущей и за- пуском новой функции будет 0,6 секунд.

Во-вторых, функция «setInterval» накапливает ошибку. Если по каким-то причинам происходят задержки таймера, то в дальнейшем они не корректируются и могут привести к отклонениям ожидаемого и реального процессов.

Часы, созданные при помощи функции «set­Interval», будут отставать от действительного времени, причем, чем дольше будет работать программа, тем сильнее будет отставание.

В-третьих, браузер может сам приостановить или замедлить работу таймера, когда страница неактивна или компьютер переходит на питание от батарей.

Также по-разному таймер может искажать свой ход при появлении диалоговых окон.

Как итог, функция «setInterval» крайне ненадежна.

Вместо нее рекомендуется использовать периодический перезапуск функции однократного отложенного запуска «setTimeout».

События.

Внутри компьютера все время происходят события, которые могут изходить как от самого пользователя (нажатие на клавиатуру), так и от программ.

Задача компьютера (операционной системы) - как можно быстрее реагировать на такие события и запускать соответствующие им программы (обработчики).

В ОС такие события называются прерываниями, в js - событиями.

Обычно, обработчики событий — это отдельные функции.

Работа системы событий связано с понятием сообщений.

Сообщение - это информация о том, что в системе произошла какое то событие.

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

Например, браузеры дополняют системные сообщения собственным набором, необходимым именно для веб-страниц.

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

Все сообщения поступают в очередь сообщений, эту очередь обслуживает специальный программный цикл - цикл событий (жизненный цикл).

Который в цикле выбирает сообщения, обрабатывает определенное сообщение (тогда и возникает событие) и запускает его обработчик.

Если для события обработчика нет, то такое сообщение просто игнорируется и удаляется из очереди.

В JavaScript принято обращаться к собы- тиям по их именам (в операционной системе — по кодам).

полный список событий браузера

В качестве обобщения события можно условно разделить на несколько групп:

  • События интерфейса пользователя;

  • События жизненного цикла;

  • Индивидуальные события.

События интерфейса пользователя возникают за счет активности пользователя веб-страницы.

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

Индивидуальные события характерны только для определенных объектов и для объектов другого типа не используются. Примером может быть событие «pause», возникающее при остановке воспроизведения (паузе) медиа-контента. Очевидно, что это событие касается только медиа-контейнеров.

Обработка событий в сценариях

Для всех стандартных событий у элементов страницы предусмотрены обработчики. Традиционно их имена формируются из префикса «on» и имени события. Например, обработчик события щелчка мыши «click» будет иметь название «onclick».

Существует несколько способов определить тело для обработчика событий.

  1. Указать его как HTML-атрибут при объявлении элемента

  2. Определить обработчик события в скриптовой части кода.

При этом по идентификатору создается одноименный объект.

  1. Задать обработчик события для элемента — это применить специальный метод «addEventListener».

Обратите внимание, в данном случае передается имя события «click» (без префикса «on», используемого для имени обработчика).

Объект event и его свойства

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

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

Информация в объекте «event» зависит от типа события, которое обрабатывается.

Еее можно разделить на ту, которая присуща всем событиям, например объект target, в котором находится целевой объект события. И информацию, присущую конкретному событию например данные о кнопке клавиатуры, или координаты указателя мыши.

Пример обработки события.

<body onclick = "out.innerText = 'Click detected over: ' + event.target.nodeName">

Т.к. мы поместили обработчик в тег body, то он будет срабатывать при нажатии на любой элемент на странице.

Таким образом событие “всплывает” наверх. Но объект target будет содержать тот элемент, на котором кликнули.

Как выглядит обьект события в консоле.

start page

Некоторые стандартизированные значения.

  • screenX, screenY — координаты курсора относительно экрана монитора;

  • pageX, pageY — координаты относительно начала веб-страницы;

  • clientX, clientY — координаты относительно клиентской части окна браузера.

Так же в событии присутствуют координаты элемента относительно родителя.

Событие передается в функцию-обработчик в качестве параметра.

element.onclick = function(e){...}

Обычно событие называют e или evt.

Управление стилями элементов web-страницы

Осуществляется установкой свойства style объекта.

function moveStranger(e){
    stranger.style.left=e.pageX+'px';
    stranger.style.top =e.pageY+'px';
}

Можно через индекс массива.

element.style["left"]

При этом т.к. - это знак вычитания и element.style.background-сolor недопустим, то используется верблюжья нотация.

element.style["background-color"] = element.style.backgroundColor

Движение мышкой.

Отличие событий mouseenter от mouseover.

Различие между этими событиями заключается в том, что события «mouseenter» и «mouseleave» получает только самый «верхний» элемент, тогда как другая пара событий «mouseover» и «mouseout» передается всем элементам, находящимся под курсором мыши.

Данный эффект называется всплытием событий (англ. bubbling или propagation).

Предположим есть 2 вложенных блока.

Событие «onmouseover» приходит дважды - сначала от блока «d2», затем от «d1».

Для управления процессом всплытия у событий предназначен метод «stopPropagation».

div1.addEventListener("click",function(e){
    console.log('Click on div1'); 
    e.stopPropagation()
})

Пример реализации функции Drug and Drop.

<style>
body{
    position: relative;
    }
    #div1 {
    background-color: tomato;
    border: 1px solid red;
    border-radius: 50%;
    height: 100px;
    width: 100px;
    position: absolute;
}
</style>



<div id="div1"></div>
<script>
    var isDrag = false;

    div1.addEventListener("mousedown",
        function(){ isDrag = true }
    )

    document.addEventListener("mouseup",
        function(){ isDrag = false }
    )

    document.addEventListener("mousemove",
        function(e){
            if(isDrag){
                div1.style.left = e.pageX + "px";
                div1.style.top = e.pageY + "px";
            }
        }
    )
</script>

События жизненного цикла

Когда Вы включаете браузер и открываете в нем новую веб-страницу происходит определенная цепочка процессов: браузер находит сервер, на котором находится страница, и запрашивает ее HTML код. Получив ответ, браузер, обрабатывает его и формирует структуру страницы, попутно загружая все элементы (картинки, скрипты и т.д.).

Описанный процесс носит название жизненного цикла веб-страницы.

Жизненный цикл веб-страницы сопровождается следующими событиями

DOMContentLoaded — браузер полностью загрузил HTML, файлы стилей и скриптов, построил структуру документа (DOM-структуру;

load — браузер загрузил все дополнительные ресурсы — изображения, фреймы;

beforeunload — браузер получил команду закрыть страницу (вкладку);

unload — браузер закрыл страницу (вкладку).

DOMContentLoaded

Событие «DOMContentLoaded» является одним из наиболее популярных среди событий жизненного цикла. Оно посылается объекту «document» тогда, когда загружен код HTML, стилевые файлы и скрипты и структура страницы уже определена.

Однако изображения и фреймы могут быть не загружены.

Обработчик события «DOMContentLoaded» подклю- чается только при помощи команды «addEventListener»:

document.addEventListener( "DOMContentLoaded" ,
    function() {
        alert("DOM loaded")
    }
)

Использование атрибутов с префиксом «on», как для большинства других событий, не даст должного эффекта.

document.onDOMContentLoaded = function() {
    alert("DOM loaded")
}

load

Событие «load» посылается после загрузки всех дополнительных ресурсов — изображений, фреймов и т.п.

Данное событие относится к объекту «window» и может быть обработано всеми допустимыми вариантами — как при помощи метода «addEventListener», так и указанием атрибутов с префиксом «on»

<body onload="alert('body loaded')">
window.onload = function() {alert('body loaded')}
window.addEventListener( "load",
    function() {
        alert('body loaded')
    })

Следует обратить внимание на то, что загрузка изображений еще не означает их отображение. Событие «load» посылается по факту окончания загрузки, но не по окончанию прорисовки. В большинстве случаев изображения хранятся в сжатых форматах, и для их вывода на страницу браузеру необходимо повести «декомпрессию» — восстановление графической информации из сжатого файла. На это уходит определенное время, которого может не хватить до вызова обработчика события.

Создадим файл index.html чтобы проследить этапы загрузки.

<!doctype html />
<html>
<head>

</head>
<body onload="alert('body loaded')">
    <img src="step.jpg" />
<script>
    document.addEventListener("DOMContentLoaded" ,
        function() {
            alert("DOM loaded")
        }
    )
</script>
</body>
</html>

Первым вызывается событие DOMContentLoaded и изображение еще не загружено и имеет статус pending.

start page

Затем происходит событие onload и изображение загружается.

start page

Поскольку дополнительные ресурсы страницы загружаются отдельно от HTML кода, для них также посылаются события об итоговом статусе. Такими событиями являются «load» и «error».

Пример отслеживания таких событий для изображения.

<img src="step.jpg"
onload="addMessage('step.jpg load OK')"
onerror="addMessage('step.jpg load error')"/>

<p id="txt"></p>
<script>
    function addMessage(msg) {
        window.txt.innerHTML += msg + "<br/>"
    }
</script>

beforeunload

Событие «beforeunload» посылается окну (объекту «window») и сигнализирует о начале закрытия (выгрузки, unload) страницы. На данном этапе можно предупредить пользователя, что на странице остались несохраненные данные, незаконченные процессы отправки или получения данных.

<!doctype html />
    <html>
    <head>
        <style>
        #text {
        height: 200px;
        width: 400px;
        }
        </style>
    </head>
    <body>
        <textarea id="text"></textarea><br/>
        <a href="http://itstep.org">IT Step</a>
        66Обработка событий
        <script>
            window.onbeforeunload =
            function(e) {
                if(text.value.length > 0) {
                    var msg = 'Text not saved';
                    e.returnValue = msg;
                    return msg;
                }
                return null;
            }
        </script>
    </body>
</html>

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

В данном случае при заполненном поле textarea пользователю не удается переход по ссылке.

start page

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

Также с целью безопасности в обработчике события «onbeforeunload» не допускается создание дополнительных диалоговых окон.

Cтандартные обработчики, запрет вызова стандартного обработчика.

Обработчики событий по умолчанию (стандартные обработчики) Для некоторых событий в браузере предусмотрены специальные стандартные обработчики, которые запускаются автоматически — без необходимости добавления их программным путем.

Например:

  • вызов контекстного меню при нажатии правой клавиши;

  • масштабирование контента при прокрутке колеса; мыши с нажатой кнопкой «Ctrl»

  • горячие клавиши и т.д.

В некоторых случаях обработчики событий по умолчанию могут мешать логике работы основного содержимого страницы.

Такие ситуации возникают, если в интерфейсе страницы используются средства управления, совпадающие с «зарезервированными» возможностями.

Рассмотрим в качестве примера следующую задачу: создать блок, который будет менять цвет при нажатии на нем клавиши мыши: зеленый, если нажата левая клавиша; синий, если средняя (или колесо), красный — если правая.

Поскольку все три клавиши мыши посылают одно и то же событие «mousedown», они устанавливают различные значения для свойства «which» объекта-события

1 — для левой клавиши

2 — для средней

3 — для правой

<div id="d1"></div>
<script>
    window.d1.onmousedown = function(e) {
        var bgColor;
        switch( e.which ) {
            case 1:
                bgColor = "lime";
                break ;
            case 2:
                bgColor = "green";
                break;
            case 3:
                bgColor = "red";
                break ;
        }

        window.d1.style.backgroundColor = bgColor;
}
</script>

Обратите внимание, что при нажатии правой клавиши кроме смены цвета на блоке появляется контекстное меню.

start page

Переопределить это поведение можно заменив стандартный обработчик события контекстного меню «oncontextmenu» для блока.

window.d1.oncontextmenu = function() { return false }

Однако не всегда удается предотвратить стандартный обработчик с помощью return false.

В таких случаях необходимо воспользоваться методом prevent­Default объекта события.

e.preventDefault();

Определение нажатия клавиш клавиатуры.

Определение статусов и кодов нажатия кнопок.

ocument.body.onkeydown = function(e)    {
    console.log(e.ctrlKey);
    console.log(e.altKey);
    console.log(e.shiftKey);
    console.log(e.key);
}

Домашнее задание.

  1. Вывести в лог страницы все события загрузки страницы

  2. Вывести несколько картинок на странице и в логе показать события завершения их загрузок.

  3. В элементе div вывести 3 картинки. Отработать клик на любой картинке и подвесить событие на div. Отобразить в логе ссылку на изображение (аттрибут src)

  4. Поместить в один блок div другой элемент div с border-radius равным 50% что превратит его в окружность. Спозиционировать его по центру родительского контейнера. Обеспечить функцию drag-and-drop перемещения окружности без рывков.

  5. Отследить все перемещения мыши внутри div и вывести в консоль ее координаты. Выводить алерт при покидании области div.

  6. Создать анимированную окружность, которая двигается внутри прямоугольного блока вправо и влево бесконечно.

  7. Отследить нажатие клавиш стрелок вправо влево и соответственно перемещать блок внутри родителя не выходя за его пределы.