Javascript урок 8. часть 2. объектная модель документа (javascript dom) и события
Содержание:
- Summary
- MouseEvent, KeyboardEvent и другие
- Распространение
- События onMouseOver и onMouseOut
- Решение в лоб
- События мыши
- Удаление привязки через removeEventListener
- JavaScript
- События через атрибуты
- Делаем по другому
- События прокрутки
- Ещё один вариант написания скрипта для onclick
- Обработчик события в виде безымянной функции
- Обработчики событий
- Пользовательские события
- Пример: Onclick в JavaScript
- Установка таймеров
- Движение мыши
- Применяем jQuery
- Особенности применения onclick для ссылки HTML
- event.preventDefault()
- Последовательность выполнения скриптов
Summary
Overall, onclick() is a type of JavaScript event that allows you to run certain code when an element on the web page is clicked.
That’s it! By using the code above, we have successfully created a webpage that will run code when we press a button. While our code above only changes text, you can make it as complicated or as simple as you would like.
If you want a user to be alerted when they click the button, you can use the alert() function in JavaScript. If you want to add “if” statements into your code, you can do that as well.
For more JavaScript learning resources, check out our How to Learn JavaScript guide.
MouseEvent, KeyboardEvent и другие
Для некоторых конкретных типов событий есть свои специфические конструкторы. Вот небольшой список конструкторов для различных событий пользовательского интерфейса, которые можно найти в спецификации UI Event:
- …
Стоит использовать их вместо , если мы хотим создавать такие события. К примеру, .
Специфический конструктор позволяет указать стандартные свойства для данного типа события.
Например, для события мыши:
Обратите внимание: этого нельзя было бы сделать с обычным конструктором. Давайте проверим:
Давайте проверим:
Впрочем, использование конкретного конструктора не является обязательным, можно обойтись , а свойства записать в объект отдельно, после создания, вот так: . Здесь это скорее вопрос удобства и желания следовать правилам. События, которые генерирует браузер, всегда имеют правильный тип.
Полный список свойств по типам событий вы найдёте в спецификации, например, .
Распространение
Обработчики событий (например, JavaScript touch events), зарегистрированные для родительских узлов, также будут принимать события, которые происходят в дочерних элементах. Если была нажата кнопка, находящаяся внутри абзаца, обработчики событий абзаца также получат событие click.
Событие распространяется от узла, в котором оно произошло, в родительский узел и в корень документа. После того, как все обработчики, зарегистрированные в конкретном узле, вступили в действие по очереди, возможность реагировать на событие получают обработчики, зарегистрированные для всего окна.
В любой момент обработчик события может вызвать для объекта события метод stopPropagation, чтобы предотвратить распространение события дальше. Это может быть полезно, когда у вас есть кнопка внутри другого интерактивного элемента, и вы не хотите, чтобы при нажатии кнопки активировалось поведение, заданное для клика мышью по внешним элементам.
В следующем примере мы регистрируем обработчики «MouseDown» как для кнопки, так и для абзаца. При клике правой клавишей (JavaScript mouse events) обработчик вызывает метод stopPropagation, который предотвращает запуск обработчика абзаца. При нажатии на кнопку другой клавишей мыши запускаются оба обработчика:
<p>Абзац и в нем <button>кнопка</button>.</p> <script> var para = document.querySelector("p"); var button = document.querySelector("button"); para.addEventListener("mousedown", function() { console.log("Handler for paragraph."); }); button.addEventListener("mousedown", function(event) { console.log("Handler for button."); if (event.which == 3) event.stopPropagation(); }); </script>
Большинство объектов событий имеют свойство target, которое указывает на узел, в котором они возникли. Вы можете использовать это свойство, чтобы случайно не обрабатывать какое-то событие, которое распространяется вверх из узла.
Также можно использовать JavaScript event target, чтобы расширить диапазон события определенного типа. Например, если у вас есть узел, содержащий длинный список кнопок, более удобно зарегистрировать один обработчик клика для внешнего узла и использовать свойство target, чтобы отслеживать, была ли нажата кнопка, а не регистрировать экземпляры обработчика для всех кнопок:
<button>A</button> <button>B</button> <button>C</button> <script> document.body.addEventListener("click", function(event) { if (event.target.nodeName == "BUTTON") console.log("Clicked", event.target.textContent); }); </script>
События onMouseOver и onMouseOut
Событие наступает при наведении () на объект и при выведении () за пределы объекта курсора мыши.
Назначение обработчика событий осуществляется точно таким же образом, как и в случае .
Поэтому выполним задание:
Задание Js8_6. По наведению курсора мыши на гиперссылки закрашивать задний фон страницы в разные цвета.
Дополните код:
<br> <a href="/" onmouseover="document.bgColor='green' ">Зеленый<a> <br> … seagreen <br> … magenta <br> … purple <br> … navy <br> … royalblue |
Задание Js8_7. Создание rollover-изображения
— Добавьте в код тег с изображением.
— Введите обработчики событий (по наведению) и (при отведении). Сделайте это в виде функций.
— Присоедините к обработчику событий процедуру загрузки в тег другого изображения.
— Присоедините к обработчику событий процедуру загрузки другого изображения в тег .
Решение в лоб
<li> <a href="#" onclick="aclick('div25');return false;">Заголовок пункта<a> <div id="div25">Текст пункта<div> <li> |
Каждому блоку вешаем уникальный ID. В ссылке прописываем обработчик, который вызывает функцию (в нашем случае aclick), передавая ей ID связанного с этой ссылкой блока. Обработчик же занимается раскрыванием/скрыванием полученного в аргументе блока.
Минусы данного решения
Первый минус — много мусора в HTML.
Второй минус более существенен. Здесь мы используем процедурное программирование со всеми его недостатками.
В чём главный недостаток процедурного программирования? В том, что данные не связаны с обрабатывающим их кодом. Вот и у нас здесь куча ссылок, куча блоков и одна функция которая их всех разруливает.
Каждому немного знающему JS очевидно, что блок нельзя раскрыть простым циклом с задержками, типа следующего:
function aclick(divid) { var div = document.getElementById(divid); div.style.height = "0"; for (var i = 10; i < 500; i += 10) { usleep(100); div.style.height = i + "px"; } } |
При таком цикле браузер просто полностью повиснет на несколько секунд. Причём в большинстве браузеров блок отрисуется только целиком в конце.
Поэтому, хотя нам этого явно не хотелось, придётся использовать таймеры и потихоньку открывать блок.
И вот у нас получается несколько параллельно идущих процессов со связанными с ними данными (таймер, состояние и т.п). И все их разруливает одна единственная функция. Несчастная функция.
Наиболее частое решение — использовать массивы значений.
var divs = {}; var timers = {}; function aclick(divid) { divsdivid = document.getElementById(divid); ... timersdivid = setInterval(...); ... } |
Массивы хранятся в глобальных переменных. Их нужно вовремя инициализовывать, сбрасывать и т.д. и т.п.
Вобщем, вместо удовольствия от любимой работы, получаем в крайнем случае удовольствие анальное.
Ещё вариант хранить данные привязанные к блоку в свойствах DOM-объекта этого блока. Уже лучше, но заморочек по прежнему хватает.
События мыши
К событиям мыши относятся:
- click — клик;
- dblclick — двойной клик;
- mouseover — наведение курсора мыши на элемент;
- mousemove — перемещение курсора мыши над элементом;
- mouseout — уведение курсора мыши с элемента;
- mousedown — нажатие левой кнопки мыши;
- mouseup — отпускание левой кнопки мыши;
- contextmenu — нажатие правой кнопки мыши и вывод контекстного меню.
Для того чтобы написать ответную реакцию на событие, создают обработчик события (event handler), который, как правило, представляет собой функцию.
Назначить обработчик события можно несколькими способами:
- ;
- ;
- ;
- .
Рассмотрим все способы.
Удаление привязки через removeEventListener
Сейчас мы с вами займемся тем,
что будем удалять привязанные к событию функции.
Что у нас будет получаться: если, к примеру, к событию onclick
привязаны функции func1 и func2, то мы сможем отвязать функцию func1,
не затрагивая func2 и наоборот.
Давайте привяжем к элементу 3 функции:
func1, func2 и func3, которые будут выводить на экран числа 1, 2 и 3:
А теперь сразу же после привязки отвяжем функции
func1 и func2. Это делается с помощью метода removeEventListener,
которая принимает те же параметры, что и addEventListener:
Понятно, что по сути мы сделали бессмысленную операцию:
привязали функции и сразу же отвязали. Давайте усложним пример и будем удалять привязку
внутри самих функций.
Пусть при первом клике на кнопку сработают все 3 функции
и при этом func1 и func2 отвяжутся от элемента. И при следующих кликах
будет срабатывать только функция func3, которую мы не отвязываем.
А в следующем примере мы ко всем кнопкам привяжем функцию
func, которая будет выводить содержимое атрибута value той кнопки,
на которую вы нажмете. А после этого функция func будет отвязываться
от этой кнопки с помощью removeEventListener. И получится что каждая кнопка
будет реагировать только на первое нажатие по ней (запустите код и проверьте это):
JavaScript
JS Array
concat()
constructor
copyWithin()
entries()
every()
fill()
filter()
find()
findIndex()
forEach()
from()
includes()
indexOf()
isArray()
join()
keys()
length
lastIndexOf()
map()
pop()
prototype
push()
reduce()
reduceRight()
reverse()
shift()
slice()
some()
sort()
splice()
toString()
unshift()
valueOf()
JS Boolean
constructor
prototype
toString()
valueOf()
JS Classes
constructor()
extends
static
super
JS Date
constructor
getDate()
getDay()
getFullYear()
getHours()
getMilliseconds()
getMinutes()
getMonth()
getSeconds()
getTime()
getTimezoneOffset()
getUTCDate()
getUTCDay()
getUTCFullYear()
getUTCHours()
getUTCMilliseconds()
getUTCMinutes()
getUTCMonth()
getUTCSeconds()
now()
parse()
prototype
setDate()
setFullYear()
setHours()
setMilliseconds()
setMinutes()
setMonth()
setSeconds()
setTime()
setUTCDate()
setUTCFullYear()
setUTCHours()
setUTCMilliseconds()
setUTCMinutes()
setUTCMonth()
setUTCSeconds()
toDateString()
toISOString()
toJSON()
toLocaleDateString()
toLocaleTimeString()
toLocaleString()
toString()
toTimeString()
toUTCString()
UTC()
valueOf()
JS Error
name
message
JS Global
decodeURI()
decodeURIComponent()
encodeURI()
encodeURIComponent()
escape()
eval()
Infinity
isFinite()
isNaN()
NaN
Number()
parseFloat()
parseInt()
String()
undefined
unescape()
JS JSON
parse()
stringify()
JS Math
abs()
acos()
acosh()
asin()
asinh()
atan()
atan2()
atanh()
cbrt()
ceil()
clz32()
cos()
cosh()
E
exp()
expm1()
floor()
fround()
LN2
LN10
log()
log10()
log1p()
log2()
LOG2E
LOG10E
max()
min()
PI
pow()
random()
round()
sign()
sin()
sqrt()
SQRT1_2
SQRT2
tan()
tanh()
trunc()
JS Number
constructor
isFinite()
isInteger()
isNaN()
isSafeInteger()
MAX_VALUE
MIN_VALUE
NEGATIVE_INFINITY
NaN
POSITIVE_INFINITY
prototype
toExponential()
toFixed()
toLocaleString()
toPrecision()
toString()
valueOf()
JS OperatorsJS RegExp
constructor
compile()
exec()
g
global
i
ignoreCase
lastIndex
m
multiline
n+
n*
n?
n{X}
n{X,Y}
n{X,}
n$
^n
?=n
?!n
source
test()
toString()
(x|y)
.
\w
\W
\d
\D
\s
\S
\b
\B
\0
\n
\f
\r
\t
\v
\xxx
\xdd
\uxxxx
JS Statements
break
class
continue
debugger
do…while
for
for…in
for…of
function
if…else
return
switch
throw
try…catch
var
while
JS String
charAt()
charCodeAt()
concat()
constructor
endsWith()
fromCharCode()
includes()
indexOf()
lastIndexOf()
length
localeCompare()
match()
prototype
repeat()
replace()
search()
slice()
split()
startsWith()
substr()
substring()
toLocaleLowerCase()
toLocaleUpperCase()
toLowerCase()
toString()
toUpperCase()
trim()
valueOf()
События через атрибуты
Вы уже хорошо знаете первый способ привязать событие к элементу —
с помощью атрибута, например onclick (если вы не помните этого
или пропустили — см. урок основы работы с событиями JavaScript).
Напомню еще раз этот способ на примере: сейчас по клику на кнопку
сработает функция func, которая выводит на экран alert:
Задания события через атрибут имеет свои недостатки:
если, к примеру, я хочу ко всем инпутам на странице привязать
определенное событие — мне придется полазить по HTML странице,
найти все инпуты и каждому добавить атрибут с событием.
Это не очень удобно и хотелось бы иметь под рукой более продвинутый способ
работы с событиями.
Поэтому давайте посмотрим, что еще нам может предложить JavaScript
при работе с событиями.
Делаем по другому
Не пишем вообще ничего лишнего в HTML, а ниже списка вставляем сценарий.
Что здесь делаем? Перебираем все элементы списка и содержащиеся в них пары ссылка-блок. Для каждой пары вызываем функцию linkAD(). Функция linkAD() связывает ссылку и блок (по нажатии ссылки открывается блок).
Что здесь нового? То что связывая ссылку и блок внутри linkAD() мы имеем дело с одной ссылкой и одним блоком. И нам абсолютно при этом не интересно сколько ещё таких блоков существует, сколько из них будут параллельно раскрываться с нашим текущим блоком и прочая и прочая…
Вызывая для каждой пары функцию мы каждый раз создаём отдельный контекст. Отдельный контекст со своими отдельными данными (timer, height, dh, cheight, a, div) привязанными только к нашему конкретному блоку.
Вложенные функции onclick() и clock() через замыкание связаны с этим контекстом. И внутри обработчика мне не нужно думать, а тот ли это timer, который относится к моему блоку и та ли это height, которая содержит высоту моего блока.
То есть мы произвели инкапсуляцию данных относящихся к одной сущности в одном месте. Маленький пример для тех, кто не понимает почему замыкания считаются аналогом ООП.
События прокрутки
Каждый раз, когда элемент прокручивается, в нем срабатывает JavaScript scroll event. Его можно использовать для отслеживания того, что в данный момент просматривает пользователь; для отключения анимации, расположенной вне окна просмотра.
В следующем примере мы выводим индикатор прогресса в правом верхнем углу документа и обновляем его, чтобы он по частям заливался другим цветом по мере прокрутки страницы вниз:
<style> .progress { border: 1px solid blue; width: 100px; position: fixed; top: 10px; right: 10px; } .progress > div { height: 12px; background: blue; width: 0%; } body { height: 2000px; } </style> <div class="progress"><div></div></div> <p>Scroll me...</p> <script> var bar = document.querySelector(".progress div"); addEventListener("scroll", function() { var max = document.body.scrollHeight - innerHeight; var percent = (pageYOffset / max) * 100; bar.style.width = percent + "%"; }); </script>
Установив для элемента свойство position или fixed, мы получим тот же результат, что и при установке position:absolute. Но так мы также блокируем прокрутку элемента вместе с остальной частью документа. В результате индикатор прогресса будет статически закреплен в верхнем углу. Внутри него находится еще один элемент, размер которого изменяется в соответствии с текущим прогрессом.
В качестве единиц измерения при установке ширины мы используем %, а не рх, чтобы размеры элемента изменялись пропорционально размеру индикатора прогресса.
Глобальная переменная innerHeight содержит высоту окна, которую мы должны вычесть из общей доступной прокручиваемой высоты документа. Нельзя прокручивать окно ниже при достижении нижней части документа. С innerHeight также может использоваться innerWidth. Разделив pageYOffset (текущую позицию окна прокрутки) на максимально допустимую позицию прокрутки и умножив на 100, мы получаем процент для индикатора прогресса.
Вызов preventDefault для JavaScript scroll event не предотвращает прокрутку. Обработчик события вызывается только после того, как происходит прокручивание.
Ещё один вариант написания скрипта для onclick
XHTML
<input type=»button» id=»button» value=»Нажмите на кнопку» />
<script>
button.onclick = function() {
alert( ‘Вот так это работает!’ );
};
</script>
1 |
<input type=»button»id=»button»value=»Нажмите на кнопку» /> <script> button.onclick=function(){ alert(‘Вот так это работает!’); }; </script> |
Заключается он в том, что мы не пишем этот атрибут для кнопки, а присваиваем ей идентификатор id=»button», а потом пишем скрипт, в котором указываем что при событии onclick по кнопке с идентификатором button срабатывает вот такой код:
PHP
alert( ‘Вот так это работает!’ );
1 | alert(‘Вот так это работает!’); |
Вот как это выглядит в действии:
Удачи вам!
С уважением Юлия Гусарь
Обработчик события в виде безымянной функции
Используется при назначении обработчиков событий для большого количества элементов. К имени события, как в предыдущем варианте, добавляется приставка «on». В примере ниже приведен код для элементов списка с . При клике на каждый из них цифра меняется на маркер в виде галочки. Для того чтобы назначить обработчик события, мы используем :
var li = document.querySelectorAll(«#rules li»);
for(let i = 0, len = li.length; i<len; i++){
li.onclick = function (){
this.style.listStyleImage = «url(markers/ok.png)»;
}
}
1 |
varli=document.querySelectorAll(«#rules li»); for(leti=,len=li.length;i<len;i++){ lii.onclick=function(){ this.style.listStyleImage=»url(markers/ok.png)»; } } |
И сам пример:
Для королевского бала необходимо:
Купить или сшить бальное платье
Сделать прическу и макияж
Научиться танцевать вальс
Выучить все правила этикета
В инспекторе свойств ( на скриншотах ниже) можно увидеть, что к каждому элементу списка добавилась кнопка с буквами (от англ. event — событие):
Если нажать на эту кнопку, то можно увидеть, какой обработчик события назначен для данного элемента и посмотреть сам код обработчика события:
Обработчики событий
Последнее обновление: 1.11.2015
Встроенные обработчики
В прошлой теме были рассмотрены встроенные обработчики (inline event handler), которые определяются в коде элемента с
помощью атрибутов:
<div id="rect" onclick="handler(event)"></div>
Хотя этот подход прекрасно работает, но он имеет кучу недостатков:
-
Код html смешивается с кодом JavaScript, в связи с чем становится труднее разрабатывать, отлаживать и поддерживать приложение
-
Обработчики событий можно задать только для уже созданных на веб-странице элементов. Динамически создаваемые элементы в этом случае
лишаются возможности обработки событий -
К элементу для одного события может быть прикреплен только один обработчик
-
Нельзя удалить обработчик без изменения кода
Свойства обработчиков событий
Проблемы, которые возникают при использовании встроенных обработчиков, были призваны решить свойства обработчиков. Подобно тому, как у html-элементов
есть атрибуты для обработчиков, так и в коде javascript у элементов DOM мы можем получить свойства обработчиков, которые соответствуют атрибутам:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <style> #rect{ width:50px; height:50px; background-color:blue; } </style> </head> <body> <div id="rect"></div> <script> function handler(e){ alert(e.type); } document.getElementById("rect").onclick = handler; </script> </body> </html>
В итоге нам достаточно взять свойство и присвоить ему функцию, используемую в качестве обработчика. За счет
этого код html отделяется от кода javascript.
Стоит также отметить, что в обработчик события браузер автоматически передает объект Event, хранящий всю информацию о событии. Поэтому
также мы можем получить этот объект в функции обработчика в качестве параметра.
Слушатели событий
Несмотря на то, что свойства обработчиков решают ряд проблем, которые связаны с использованием атрибутов, в то же время это также
не оптимальный подход. Еще один способ установки обработчиков событий представляет использование слушателей.
Для работы со слушателями событий в JavaScript есть объект EventTarget, который определяет методы
addEventListener() (для добавления слушателя) и removeEventListener()
для удаления слушателя. И поскольку html-элементы DOM тоже являются объектами EventTarget, то они также имеют эти методы. Фактически слушатели представляют те же функции обработчиков.
Метод принимает два параметра: название события без префикса on и функцию обработчика этого события. Например:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <style> #rect{ width:50px; height:50px; background-color:blue; } </style> </head> <body> <div id="rect"></div> <script> var rect = document.getElementById("rect"); rect.addEventListener("click", function (e) { alert(e.type); }); </script> </body> </html>
То есть в данном случае опять же обрабатывается событие click. И также можно было бы в качестве второго параметра название функции:
function handler(e){ alert(e.type); } var rect = document.getElementById("rect"); rect.addEventListener("click", handler);
Удаление слушателя аналогично добавлению:
rect.removeEventListener("click", handler);
Преимуществом использования слушателей является и то, что мы можем установить для одного события несколько функций:
var clicks = 0; function handlerOne(e){ alert(e.type); } function handlerTwo(e){ clicks++; var newNode = document.createElement("p"); newNode.textContent = "произошло нажатие " + clicks; document.body.appendChild(newNode); } var rect = document.getElementById("rect"); // прикрепляем первый обработчик rect.addEventListener("click", handlerOne); // прикрепляем второй обработчик rect.addEventListener("click", handlerTwo);
НазадВперед
Пользовательские события
Для генерации событий совершенно новых типов, таких как , следует использовать конструктор . Технически абсолютно идентичен за исключением одной небольшой детали.
У второго аргумента-объекта есть дополнительное свойство , в котором можно указывать информацию для передачи в событие.
Например:
Свойство может содержать любые данные. Надо сказать, что никто не мешает и в обычное записать любые свойства. Но предоставляет специальное поле во избежание конфликтов с другими свойствами события.
Кроме того, класс события описывает, что это за событие, и если оно не браузерное, а пользовательское, то лучше использовать , чтобы явно об этом сказать.
Пример: Onclick в JavaScript
object
Чтобы это понять, нам понадобится кнопка… button
<button id=»onclick_v_javascript»>Это второй способ реализации Onclick в JavaScript</button>
idquerySelector-adocument.querySelector(«#onclick_v_javascript»).onclick = function(){alert(«Это второй способ реализации Onclick в JavaScript»);};
Соберем все вместе:
<button id=»onclick_v_javascript»>Это второй способ реализации Onclick в JavaScript</button>
<script>document.querySelector(«#onclick_v_javascript»).onclick = function(){alert(«Это второй способ реализации Onclick в JavaScript и вывод через alert»);}; </script>
Результат:
Это второй способ реализации Onclick в JavaScript
Установка таймеров
Функция setTimeout похожа на requestAnimationFrame. Она задает вызов еще одной функции, которая будет вызываться позже. Но вместо того, чтобы вызывать функцию при следующем формировании страницы, она ждет определенное количество миллисекунд. В этом примере JavaScript event фон страницы из синего становится желтым через две секунды:
<script> document.body.style.background = "blue"; setTimeout(function() { document.body.style.background = "yellow"; }, 2000); </script>
Иногда нужно отменить функцию, которую мы запланировали. Это делается путем сохранения значения, возвращаемого функцией setTimeout, и вызова для нее clearTimeout:
var bombTimer = setTimeout(function() { console.log("BOOM!"); }, 500); if (Math.random() < 0.5) { // 50% chance console.log("Defused."); clearTimeout(bombTimer); }
Функция cancelAnimationFrame работает так же, как clearTimeout. Она вызывается значением, возвращаемым requestAnimationFrame, чтобы отменить кадр (если он еще не был вызван).
Похожий набор функций, setInterval и clearInterval используется для установки таймера, который должен повторять действие каждые X миллисекунд:
var ticks = 0; var clock = setInterval(function() { console.log("tick", ticks++); if (ticks == 10) { clearInterval(clock); console.log("stop."); } }, 200);
Движение мыши
Каждый раз, когда перемещается курсов мыши, срабатывает событие «mousemove» из набора JavaScript mouse events. Оно может быть использовано для отслеживания положения мыши. Это применяется при реализации возможности перетаскивания элементов мышью.
В следующем примере программа выводит на экран панель и устанавливает обработчики событий таким образом, что при перетаскивании эта панель становится уже или шире:
<p>Потяните за край панели, чтобы изменить ее ширину:</p> <div style="background: orange; width: 60px; height: 20px"> </div> <script> var lastX; // Отслеживает последнюю позицию X мыши var rect = document.querySelector("div"); rect.addEventListener("mousedown", function(event) { if (event.which == 1) { lastX = event.pageX; addEventListener("mousemove", moved); event.preventDefault(); // Предотвращает выделение } }); function buttonPressed(event) { if (event.buttons == null) return event.which != 0; else return event.buttons != 0; } function moved(event) { if (!buttonPressed(event)) { removeEventListener("mousemove", moved); } else { var dist = event.pageX - lastX; var newWidth = Math.max(10, rect.offsetWidth + dist); rect.style.width = newWidth + "px"; lastX = event.pageX; } } </script>
Обратите внимание, что обработчик «mousemove» зарегистрирован для всего окна. Даже если во время изменения размеров мышь выходит за пределы панели, мы все равно обновляем ширину панели и прекращаем JavaScript touch events, когда клавиша мыши была отпущена
Мы должны прекратить изменение размера панели, когда пользователь отпускает клавишу мыши. К сожалению, не все браузеры устанавливают для событий «mousemove» свойство which. Существует стандартное свойство buttons, которое предоставляет аналогичную информацию, но оно также поддерживается не во всех браузерах. К счастью, все основные браузеры поддерживают что-то одно: либо buttons, либо which. Функция buttonPressed в приведенном выше примере сначала пытается использовать свойство buttons, и, если оно не доступно, переходит к which.
Когда курсор мыши наводится или покидает узел, запускаются события «mouseover» или «mouseout«. Они могут использоваться для создания эффектов при наведении курсора мыши, вывода какой-нибудь подписи или изменения стиля элемента.
Чтобы создать такой эффект, недостаточно просто начать его отображение при возникновении события «mouseover» и завершить после события «mouseout«. Когда мышь перемещается от узла к одному из его дочерних элементов, для родительского узла происходит событие «mouseout«. Хотя указатель мыши не покинул диапазон распространения узла.
Что еще хуже, эти JavaScript event распространяются так же, как и другие события. Когда мышь покидает один из дочерних узлов, для которого зарегистрирован обработчик, возникнет событие «mouseout«.
Чтобы обойти эту проблему, можно использовать свойство объекта события relatedTarget. В случае возникновения события «mouseover» оно указывает, на какой элемент был наведен курсор мыши до этого. А в случае возникновения «mouseout» — к какому элементу перемещается указатель. Мы будем изменять эффект наведения мыши только, когда relatedTarget находится вне нашего целевого узла.
В этом случае мы изменяем поведение, потому что курсор мыши был наведен на узел из-за его пределов (или наоборот):
<p>Наведите курсор мыши на этот <strong>абзац</strong>.</p> <script> var para = document.querySelector("p"); function isInside(node, target) { for (; node != null; node = node.parentNode) if (node == target) return true; } para.addEventListener("mouseover", function(event) { if (!isInside(event.relatedTarget, para)) para.style.color = "red"; }); para.addEventListener("mouseout", function(event) { if (!isInside(event.relatedTarget, para)) para.style.color = ""; }); </script>
Функция isInside отслеживает родительские связи заданного узла или пока не будет достигнута верхняя часть документа (когда node равен нулю). Либо не будет найден родительский элемент, который нам нужен.
Эффект наведения гораздо проще создать с помощью псевдоселектора CSS :hover, как показано в следующем примере. Но когда эффект наведения предполагает что-то более сложное, чем просто изменение стиля целевого узла, тогда нужно использовать прием с использованием событий «mouseover» и «mouseout» (JavaScript mouse events):
<style> p:hover { color: red } </style> <p>Наведите курсор мыши на этот <strong>абзац</strong>.</p>
Применяем jQuery
Если в проекте используется библиотека jQuery, то можно ещё упростить код. Рассмотрим два самых распространенных способа:
$(function(){ $(".link").click(function() { //действия }); });
И ещё один вариант, который идентичен предыдущему.
$(function(){ $(".link").on("click", function(){ //действия }); });
С обработчиком «on()» лучше ознакомиться отдельно, так как он несет в себе много полезного функционала. Например, возможность указать через пробел несколько событий к которым будет применяться действие, делегировать события на дочерние элементы, а так же он полезен если необходимо повесить событие на динамически добавляемые элементы, которых изначально нет на странице.
Особенности применения onclick для ссылки HTML
HTML код написания этого атрибута в теге ссылки выглядит так:
PHP
<a title=»Ссылка» href=»#» onclick=» alert(‘Ку-ку!’)»»>Нажми на меня!</a>
1 | <atitle=»Ссылка»href=»#»onclick=» alert(‘Ку-ку!’)»»>Нажминаменя!<a> |
Это позволяет нам добиться того чтобы браузер проигнорировал то что написано внутри атрибута href и никуда не переходил.
Вы наверное спросите: «А зачем тогда вообще оставлять атрибут href? Удалили его и все дела!»
В принципе такой вариант тоже возможен и он будет работать, НО с точки зрения валидности HTML кода это не есть хорошо, так как этот атрибут является основным и неотъемлемым для ссылки и удаляя его вы коварно лишаете ссылку важнейшей части её «тела». Валидаторы вам этого не простят!
Внутри атрибута href можно задать следующие значения:
- оставить его пустым href=»»
- поставить в нём решётку href=»#»
- написать href=»javascript://»
- указать реальную ссылку своего сайта href=» //impuls-web.ru/»
Мне больше нравится вариант с javascript:// и #.
Так же артибут onclick можно применять и к любым другим HTML тегам, но это будет скорее из области изощрений и извращений, так как в HTML для событий клика предназначены кнопки и ссылки, поэтому тулить события щелчка к другим тегам как то не очень целесообразно.
event.preventDefault()
Для новых, пользовательских событий браузерных действий, конечно, нет, но код, который генерирует такое событие, может предусматривать какие-то свои действия после события.
Вызов является возможностью для обработчика события сообщить в сгенерировавший событие код, что эти действия надо отменить.
Тогда вызов возвратит . И код, сгенерировавший событие, узнает, что продолжать не нужно.
Посмотрим практический пример – прячущегося кролика (могло бы быть скрывающееся меню или что-то ещё).
Ниже вы можете видеть кролика и функцию , которая при вызове генерирует на нём событие , уведомляя всех интересующихся, что кролик собирается спрятаться.
Любой обработчик может узнать об этом, подписавшись на событие через и, при желании, отменить действие по умолчанию через . Тогда кролик не исчезнет:
Обратите внимание: событие должно содержать флаг. Иначе, вызов будет проигнорирован
Последовательность выполнения скриптов
Запустить выполнение скрипта могут разные факторы: считывание тега , возникновение события. Метод requestAnimationFrame, задает вызов функции, перед тем как будет заново построена следующая страница. Это еще один способ, с помощью которого могут запускаться скрипты.
События JavaScript select events и все остальные могут запускаться в любой момент, но в одном документе два скрипта никогда не запустятся одновременно. Если скрипт уже выполняется, обработчикам событий и фрагментам кода, запланированным другим скриптом, придется подождать своей очереди. Именно по этой причине документ замирает, когда скрипт работает в течение длительного времени. Браузер не реагирует на клики и другие события, поскольку не может запустить обработчики событий, пока текущий скрипт не закончит работу.
Некоторые среды программирования позволяют создавать несколько потоков исполнения, которые запускаются одновременно. Обеспечив возможность выполнять одновременно несколько задач, можно повысить скорость выполнения программы. Но когда у нас есть несколько действий, которые затрагивают те же части системы одновременно, программе становится сложнее выполнять их.
Если нужно запустить процессы в фоновом режиме без замораживания страницы, браузеры предоставляют нам то, что называется web workers. Это изолированная среда JavaScript, которая работает с документом вместе с основной программой и может общаться с ним только путем отправки и получения сообщений.
Предположим, что в файле с именем code/squareworker.js у нас есть следующий код:
addEventListener("сообщение", function(event) { postMessage(event.data * event.data); });
Представьте себе, что возводимое в квадрат число является очень большим, затягивающим вычисление, и нужно выполнить вычисления в фоновом потоке. Этот код запускает web workers, посылает ему несколько сообщений и выводит ответы:
var squareWorker = new Worker("code/squareworker.js"); squareWorker.addEventListener("message", function(event) { console.log("The worker responded:", event.data); }); squareWorker.postMessage(10); squareWorker.postMessage(24);
Функция postMessage отправляет сообщение, которое инициирует возникновение в приемнике события «message«. Скрипт, который создал web workers, отправляет и получает сообщения через объект Worker. С помощью этого объекта среда взаимодействуют с создавшим ее скриптом, посылая информацию и прослушивая его в своем глобальном с оригинальным скриптом.