Javascript урок 8. часть 2. объектная модель документа (javascript dom) и события

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.

Координаты в окне: clientX/Y

Все мышиные события предоставляют текущие координаты курсора в двух видах: относительно окна и относительно документа.

Пара свойств содержит координаты курсора относительно текущего окна.

При этом, например, если ваше окно размером 500×500, а мышь находится в центре, тогда и и будут равны 250.

Можно как угодно прокручивать страницу, но если не двигать при этом мышь, то координаты курсора не изменятся, потому что они считаются относительно окна, а не документа.

Проведите мышью над полем ввода, чтобы увидеть :

В той же системе координат работает и метод , возвращающий координаты элемента, а также .

Координаты курсора относительно документа находятся в свойствах .

Так как эти координаты – относительно левого-верхнего узла документа, а не окна, то они учитывают прокрутку. Если прокрутить страницу, а мышь не трогать, то координаты курсора изменятся на величину прокрутки, они привязаны к конкретной точке в документе.

В IE8- этих свойств нет, но можно получить их способом, описанным в конце главы.

Проведите мышью над полем ввода, чтобы увидеть (кроме IE8-):

В той же системе координат работает , если элемент позиционируется относительно документа.

Устарели:

Некоторые браузеры поддерживают свойства , .

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

События мыши

К событиям мыши относятся:

  • click — клик;
  • dblclick — двойной клик;
  • mouseover — наведение курсора мыши на элемент;
  • mousemove — перемещение курсора мыши над элементом;
  • mouseout — уведение курсора мыши с элемента;
  • mousedown — нажатие левой кнопки мыши;
  • mouseup — отпускание левой кнопки мыши;
  • contextmenu — нажатие правой кнопки мыши и вывод контекстного меню.

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

Назначить обработчик события можно несколькими способами:

  1. ;
  2. ;
  3. ;
  4. .

Рассмотрим все способы.

Объект «событие» (event)

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

Способов передачи этого объекта обработчику существует ровно два, и они зависят от способа его установки и от браузера.

В браузерах, работающих по рекомендациям W3C, объект события всегда передается в обработчик первым параметром.

Например:

function doSomething(event) {
	// event - будет содержать объект события
}

element.onclick = doSomething;

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

Можно назначить и вот так:

element.onclick = function(event) {
	// event - объект события
}

Интересный побочный эффект — в возможности использования переменной при назначении обработчика в HTML:

<input type="button" onclick="alert(event)" value="Жми сюда не ошибешься"/>

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

В Internet Explorer существует глобальный объект , который хранит в себе информацию о последнем событии. А первого аргумента обработчика просто нет.

То есть, все должно работать так:

// обработчик без аргументов
function doSomething() {
	// window.event - объект события
}

element.onclick = doSomething;

Обратите внимание, что доступ к при назначении обработчика в HTML (см. пример выше) по-прежнему будет работать

Такой вот надежный и простой кросс-браузерный доступ к объекту события.

Можно кросс-браузерно получить объект события, использовав такой приём:

function doSomething(event) {
    event = event || window.event

    // Теперь event - объект события во всех браузерах.
}

element.onclick = doSomething

Как мы уже говорили раньше, при описании обработчика события в HTML-разметке для получения события можно использовать переменную с названием .

<input type="button" onclick="alert(event.type)" value="Нажми меня"/>

Этот код в действии:

Это совершенно кросс-браузерный способ, так как по стандарту — название первого аргумента функции-обработчика, которую автоматом создаст браузер; ну а в IE значение будет взято из глобального объекта .

Обработчик события в виде безымянной функции

Используется при назначении обработчиков событий для большого количества элементов. К имени события, как в предыдущем варианте, добавляется приставка «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
2
3
4
5
6

varli=document.querySelectorAll(«#rules li»);

for(leti=,len=li.length;i<len;i++){

lii.onclick=function(){

this.style.listStyleImage=»url(markers/ok.png)»;

}

}

И сам пример:

Для королевского бала необходимо:

Купить или сшить бальное платье
Сделать прическу и макияж
Научиться танцевать вальс
Выучить все правила этикета

В инспекторе свойств ( на скриншотах ниже) можно увидеть, что к каждому элементу списка добавилась кнопка с буквами (от англ. event — событие):

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

javascript onclick без клика

javascript onclick без клика

но первое, что я подумал… вспомнил старый пошлый анекдот! дети, если вам нет 16, то закрываем страницу на этом месте!

Закрыли!? Я жду!

Теперь продолжим со взрослыми…

Встречается парочка на хате, а у парня был попугай! Девушка:

— я не могу заниматься этим, когда он смотрит…

Парень накинул тряпку на клетку.

И говорит попугаю! Будешь подсматривать — голову оторву!

Начали заниматься любовью!

— Давай я сверху, ты снизу!

— Давай!

— Давай ты сверху, я снизу!

— Давай!

— А теперь давай ты сверху, и я сверху!

Попугай:

— Пусть мне оторвут голову! Но это я должен увидеть!

События через работу с атрибутами

По сути атрибут onclick является таким же атрибутом,
как, к примеру, value.
И, если мы могли менять атрибут value таким образом — elem.value,
то точно также мы можем менять атрибут onclick.

Если мы сделаем так: elem.onclick = func, то привяжем к элементу elem
функцию func. Посмотрите пример и под ним мы обсудим все нюансы этого способа:

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

Я уверен, что прочитав это, вы не до конца поймете то, что я хотел вам донести,
поэтому запустите пример и еще раз перечитайте предыдущий абзац.
Вот пример:

Теперь, зная эту страшную тайну, вернемся к строке elem.onclick = func — в данном случае
я в атрибут onclick записываю исходный код функции, а не ее результат — и все работает.
Если вы сделаете так — elem.onclick = func() — то запишите результат функции и ничего не будет
работать.

Кстати, результатом функции func() будет undefined,
так как у нее нет команды return.
Напомню код функции, о которой идет речь:

Давайте вспомним метод setInterval
(см. урок работа с таймерами в JavaScript),
когда мы использовали его таким образом window.setInterval(timer, 1000)
в этом случае мы также писали функцию timer без круглых скобок,
потому что нас интересовал не результат работы функции, а ее код.

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

Для каких элементов можно использовать атрибут onclick в HTML?

Синтаксис написание этого атрибута выглядит так:

XHTML

<input type=»button» onclick=»alert(‘Привет! Вот так работает этот скрипт’)» value=»Нажми на меня!»/>

1 <input type=»button»onclick=»alert(‘Привет! Вот так работает этот скрипт’)»value=»Нажми на меня!»/>

Давайте разберём что же означает набор этих странных символов.

В данном примере мы задаём атрибут onclick для кнопки button. Чтобы браузер понял что нам нужна именно кнопка мы указываем тип type=»button». Далее в этом атрибуте мы пишем javascript код.

В данном случае мы вызываем модальное окно и выводим в нём текст при помощи метода alert():

XHTML

onclick=»alert(‘Привет! Вот так работает этот скрипт’)»

1 onclick=»alert(‘Привет! Вот так работает этот скрипт’)»

В скобках в кавычках указываем текст, который нужно вывести.

И последнее задаём текст, который будет написан на кнопке при помощи value=»Нажми на меня!»

А вот так будет выглядеть это чудо в действии:

Кроме кнопок атрибут onclick можно применять к ссылкам и к любым другим тегам HTML, НО там есть свои особенности, о которых поговорим ниже.

Click в jQuery с использованием -> класса(class)

click в jQuery

Нам опять понадобится какая-то кнопка с классом(пусть будет THEclass), чтобы увидеть реальное действие click в jQuery.

<button class=»THEclass»>Кнопка button с классом THEclass</button>

Скрипт клика абсолютно аналогичный, что бы приведен выше! Но только внутри первых скобок помести класс и вместо решетки ставим точку — она, как вы знаете обозначает класс в css

И внутри помещаем тот же скрипт script, который выполнит ту же работу!

Соберем весь код клика по кнопке с классом в jQuery:

<button class=»THEclass»>Кнопка button с классом THEclass</button>

<script>

$( «.THEclass» ).click(function() {

alert( $(«.THEclass»).html() );

});

</script>

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

Браузер имеет своё собственное поведение по умолчанию для различных событий.

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

element.onclick = function(event) {
    event = event || window.event 

    if (event.preventDefault) {
        // Вариант стандарта W3C: 
        event.preventDefault()
    } else {
        // Вариант Internet Explorer:
        event.returnValue = false
    }
}

Вместо можно записать одну строчку:

..
event.preventDefault ? event.preventDefault() : (event.returnValue=false)
...

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

Например, при фокусировке на ссылке — браузер выделяет ее пунктирной рамочкой.
Это действие выполняется до события , поэтому отменить выделение в обработчике нельзя.

При клике перехода не произойдет, а рамка вокруг ссылки появится.

Код примера:

var a = document.getElementById('my-focus-a')
a.onfocus = a.onclick = function(e) {
    e = e || window.event
    // другая кроссбраузерная запись остановки события
    e.preventDefault ? e.preventDefault() : (e.returnValue=false)
}

Типы событий мыши

Условно можно разделить события на два типа: «простые» и «комплексные».

Кнопка мыши нажата над элементом.
Кнопка мыши отпущена над элементом.
Мышь появилась над элементом.
Мышь ушла с элемента.
Каждое движение мыши над элементом генерирует это событие.
Вызывается при клике мышью, то есть при , а затем на одном элементе
Вызывается при клике правой кнопкой мыши на элементе.
Вызывается при двойном клике по элементу.

Комплексные можно составить из простых, поэтому в теории можно было бы обойтись вообще без них. Но они есть, и это хорошо, потому что с ними удобнее.

Одно действие может вызывать несколько событий.

Например, клик вызывает сначала при нажатии, а затем и при отпускании кнопки.

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

Кликните по кнопке ниже и вы увидите, какие при этом происходят события. Попробуйте также двойной клик.

На тест-стенде ниже все мышиные события записываются, и если между событиями проходит больше 1 секунды, то они для удобства чтения отделяются линией. Также присутствуют свойства , по которым можно определить кнопку мыши. Мы их рассмотрим далее.

Каждое событие обрабатывается независимо.

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

Несколько обработчиков одного и того же события

В javascript можно назначать НЕСКОЛЬКО обработчиков одного и того же события. Для этого используются методы:

addEventListener — добавление обработчика

removeEventListener — удаление обработчика

Пример: Щелкнув по кнопке вызвать диалоговое окно со словом Ура!. Выполнить задание, используя метод addEventListener.

Решение: 

  • html код:
<input type="button" value="кнопка" id="MyElem">

скрипт:

<script type="text/javaScript"> 
function message() {
	alert('Ура!');
}
var input = document.getElementById("MyElem"); 
input.addEventListener("click", message);
</script>

Пример: В предыдущем задании удалить добавленный обработчик с кнопки, используя метод removeEventListener.

Решение: 

<script type="text/javaScript"> 
function message() {
	alert('Ура!');
}
var input = document.getElementById("MyElem"); 
input.addEventListener("click", message);
input.removeEventListener("click", message);
</script>

Всплытие и погружение события

obj.onevent = function(e) {/*...*/}
// где e - объект события
// e.target - элемент, на котором произошло событие

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()

Добавление обработчика через свойство DOM объекта

Второй способ назначить обработчик — это использовать свойство .

Например, привяжем обработчик события к элементу (для этого события свойство будет ):

<!-- HTML код кнопки -->
<button type="button" id="my-btn">Нажми на меня</button>

<!-- Скрипт на JavaScript -->
<script>
// получим кнопку и сохраним ссылку на неё в переменную
const $btn = document.querySelector('#my-btn');
// добавим к $btn обработчик события click
$btn.onclick = function() {
  alert('Вы кликнули на кнопку!');
}
</script>

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

Другой вариант – это назначить уже существующую функцию.

Например:

function changeBgColor() {
  document.body.style.backgroundColor = `rgb(${Math.round(Math.random()*255)}, ${Math.round(Math.random()*255)}, ${Math.round(Math.random()*255)})`;
}

document.onclick = changeBgColor;

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

Например:

<!-- HTML код кнопок -->
<button type="button">Кнопка 1</button>
<button type="button">Кнопка 2</button>
<button type="button">Кнопка 3</button>

<!-- Скрипт на JavaScript -->
<script>
function message() {
  // this - обращаемся к кнопке для которой вызван обработчик
  alert(this.textContent);
}
// получим кнопки и сохраним ссылки на них в переменную $btns
const $btns = document.querySelectorAll('button');
// переберём кнопки и добавим к ним обработчик, используя onclick
$btns.forEach(function($element) {
  $element.onclick = message;
});
</script>

Кстати, когда обработчик задаётся через атрибут, то браузер самостоятельно при чтении такого HTML создаёт из значения этого атрибута функцию и присваивает её одноименному свойству этого элемента.

Например:

<button id="btn" type="button" onclick="alert('Вы кликнули на кнопку')">Кнопка</button>

<script>
const $element = document.querySelector('#btn');
// получим значение свойства onclick (как видно браузер туда автоматически записал функцию, которую создал на основании содержимого этого атрибута)
console.log($element.onclick);
</script>

Т.е., по сути, задание свойства через атрибут – это просто способ инициализации обработчика. Т.к. сам обработчик в этом случае тоже хранится в свойстве DOM-объекта.

Но установка обработчика через свойство имеет недостаток. С помощью него нельзя назначить одному событию несколько обработчиков. Если в коде создадим новый обработчик, то он перезапишет существующий:

<button id="btn" type="button">Кнопка</button>

<script>
  const $element = document.querySelector('#btn');

  $element.onclick = function () {
    alert(`id = ${this.id}`);
  }
  // заменит предыдущий обработчик
  $element.onclick = function () {
    alert(`text = ${this.textContent}`);
  }
</script>

Кстати, также не получится назначить несколько обработчиков, один через атрибут, а другой через свойство. Последний перепишет предыдущий.

<button id="btn" type="button" onclick="alert(`id = ${this.id}`);">Кнопка</button>

<script>
  const $element = document.querySelector('#btn');
  // заменит обработчик, инициализированный с помощью атрибута
  $element.onclick = function () {
    alert(`text = ${this.textContent}`);
  }
</script>

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

Событию можно назначить обработчик, то есть функцию, которая сработает, как только событие произошло.

Именно благодаря обработчикам JavaScript-код может реагировать на действия пользователя.

Есть несколько способов назначить событию обработчик. Сейчас мы их рассмотрим, начиная с самого простого.

Обработчик может быть назначен прямо в разметке, в атрибуте, который называется .

Например, чтобы назначить обработчик события на элементе , можно использовать атрибут , вот так:

При клике мышкой на кнопке выполнится код, указанный в атрибуте .

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

Атрибут HTML-тега – не самое удобное место для написания большого количества кода, поэтому лучше создать отдельную JavaScript-функцию и вызвать её там.

Следующий пример по клику запускает функцию :

Как мы помним, атрибут HTML-тега не чувствителен к регистру, поэтому будет работать так же, как и … Но, как правило, атрибуты пишут в нижнем регистре: .

Можно назначать обработчик, используя свойство DOM-элемента .

К примеру, :

Если обработчик задан через атрибут, то браузер читает HTML-разметку, создаёт новую функцию из содержимого атрибута и записывает в свойство.

Этот способ, по сути, аналогичен предыдущему.

Обработчик всегда хранится в свойстве DOM-объекта, а атрибут – лишь один из способов его инициализации.

Эти два примера кода работают одинаково:

  1. Только HTML:

  2. HTML + JS:

Так как у элемента DOM может быть только одно свойство с именем , то назначить более одного обработчика так нельзя.

В примере ниже назначение через JavaScript перезапишет обработчик из атрибута:

Кстати, обработчиком можно назначить и уже существующую функцию:

Убрать обработчик можно назначением .

Вешаем onclick на элемент из javascript-кода

Рассмотим еще один способ, на мой взгляд, самый практичный и надежный. Хорош он тем, что событие можно повесить на множество элементов. Для этого требуется выбрать при помощи javascript-селекторов элементы, к которым требуется применить событие onclick.

Код в действии:

Нажмите на ссылку:

Выбору элементов по селекторам можно посвятить отдельную тему, могу сказать только то, что согласно новой спецификации HTML5, их выбор стал прост и в javascript. Если Вы знакомы с jquery или CSS, то выбрать нужные элементы для Вас не составит труда. Например, так просто можно выбрать все элементы с классом «link» и повесить на них нужное действие:

//выбираем нужные элементы
var a = document.querySelectorAll('.link');
    
//перебираем все найденные элементы и вешаем на них события
[].forEach.call( a, function(el) {
    //вешаем событие
    el.onclick = function(e) {
        //производим действия
    }
});

Работа с addEventListener

Метод addEventListener первым параметром принимает название события,
а вторым — функцию, которую нужно привязать к этому событию.
При этом имя события пишется без ‘on’: ‘click’ вместо ‘onclick’,
‘mouseover’ вместо ‘onmouseover’ и так далее. Имя функции (второй параметр)
пишется без кавычек и без круглых скобок (зачем это нужно, мы с вами уже разобрали выше).

Давайте сделаем так, чтобы по клику на кнопку вызывалась функция func:

Привяжем теперь одновременно два события. При этом таких проблем,
как в предыдущем случае у нас не возникнет — события не будут затирать друг друга,
сколько бы их не объявили:

Особенности применения 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.defaultPrevented

Свойство установлено в , если действие по умолчанию было предотвращено, и , если нет.

Рассмотрим практическое применение этого свойства для улучшения архитектуры.

Помните, в главе Всплытие и погружение мы говорили о и упоминали, что останавливать «всплытие» – плохо?

Иногда вместо этого мы можем использовать , чтобы просигналить другим обработчикам, что событие обработано.

Давайте посмотрим практический пример.

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

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

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

Проблема заключается в том, что когда мы кликаем по элементу , то мы получаем два меню: контекстное меню для кнопки и (событие всплывает вверх) контекстное меню для документа.

Как это поправить? Одно из решений – это подумать: «Когда мы обрабатываем правый клик в обработчике на кнопке, остановим всплытие», и вызвать :

Теперь контекстное меню для кнопки работает как задумано. Но цена слишком высока. Мы навсегда запретили доступ к информации о правых кликах для любого внешнего кода, включая счётчики, которые могли бы собирать статистику, и т.п. Это слегка неразумно.

Альтернативным решением было бы проверить в обработчике , было ли отменено действие по умолчанию? Если да, тогда событие было обработано, и нам не нужно на него реагировать.

Сейчас всё работает правильно. Если у нас есть вложенные элементы и каждый из них имеет контекстное меню, то код также будет работать. Просто убедитесь, что проверяете в каждом обработчике .

event.stopPropagation() и event.preventDefault()

Как мы можем видеть, и (также известный как ) – это две разные функции. Они никак не связаны друг с другом.

Архитектура вложенных контекстных меню

Есть также несколько альтернативных путей, чтобы реализовать вложенные контекстные меню. Одним из них является единый глобальный объект с обработчиком и методами, позволяющими хранить в нём другие обработчики.

Объект будет перехватывать любой клик правой кнопкой мыши, просматривать сохранённые обработчики и запускать соответствующий.

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

JavaScript onclick

The JavaScript onclick event executes a function when you click on a button or another web element. For instance, an onclick event can trigger a dialog box to appear when you clock on a button.

Here is the syntax for the onclick method in HTML:

&lt;button onclick="codetorun"&gt;Click me&lt;/button&gt;

When this HTML button is clicked, the “codetorun” JavaScript function will execute. We can use onclick with other elements, like a div. onclick is not exclusive to buttons.

You can also use onclick in plain JavaScript. Here is an example of a JavaScript onclick method:

var item = document.getElementById("button");
item.onclick = function() {
	codetoexecute...
}

We use the JavaScript getElementById method to retrieve an element from our web page. When we click on the element with the ID “button” our onclick function will execute.

Демонстрация

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

Полная демонстрация атаки:

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

В результате, если пользователь авторизован на сайте Facebook («Запомнить меня» обычно активировано), то он добавляет «лайк». В Twitter это будет кнопка «читать», и т.п.

Вот тот же пример, но более приближенный к реальности с для :

Clickjacking-атака для кликов мыши, а не для клавиатуры

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

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

Но есть одна проблема. Всё, что посетитель печатает, будет скрыто, потому что ифрейм не виден.

Обычно люди перестают печатать, когда не видят на экране новых символов.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector