предисловие
В этой статье в основном представлены общие приложения уровня событий DOM, модели событий DOM, потока событий, прокси-сервера события и объекта события.Я надеюсь, что это поможет и вдохновит вас!
Первый адрес этой статьиБлог GitHub, Писать статьи непросто, поддержите и обратите внимание!
1. Уровень события DOM
Уровень DOM можно разделить на четыре уровня: уровень DOM0, уровень DOM1, уровень DOM2 и уровень DOM3. а такжеСобытия DOM делятся на 3 уровня: обработка событий DOM уровня 0, обработка событий DOM уровня 2 и обработка событий DOM уровня 3.. События уровня 1 DOM отсутствуют, поскольку в уровне DOM 1 нет связанного с событиями контента.
1. События уровня DOM 0
el.onclick=function(){}
// 例1
var btn = document.getElementById('btn');
btn.onclick = function(){
alert(this.innerHTML);
}
Если вы хотите привязать несколько событий одного типа к одному и тому же элементу/метке (например, привязать 3 события щелчка к элементу btn выше), это не разрешено.. привязка события DOM0, метод привязки к поведению элемента,Эти методы выполняются в фазе всплытия (или целевой фазе) текущего поведения события элемента..
2. События DOM уровня 2
el.addEventListener(event-name, callback, useCapture)
- event-name: имя события, может быть стандартным событием DOM
- callback: функция обратного вызова, когда событие срабатывает, функция будет введена с параметром текущего объекта события event
- useCapture: значение по умолчанию — false, что означает, что обработчик событий выполняется во время фазы всплытия.
// 例2
var btn = document.getElementById('btn');
btn.addEventListener("click", test, false);
function test(e){
e = e || window.event;
alert((e.target || e.srcElement).innerHTML);
btn.removeEventListener("click", test)
}
//IE9-:attachEvent()与detachEvent()。
//IE9+/chrom/FF:addEventListener()和removeEventListener()
Браузеры IE ниже IE9 не поддерживают addEventListener() и removeEventListener(), вместо этого используйте attachEvent() и detachEvent(), поскольку IE9 и ниже не поддерживают захват событий, поэтому третьего параметра перед именем первого события нет. .
3. События DOM уровня 3
Добавлено больше типов событий поверх событий уровня DOM 2.
- События пользовательского интерфейса, срабатывающие, когда пользователь взаимодействует с элементами на странице, например: загрузка, прокрутка
- Событие фокуса, срабатывающее, когда элемент получает или теряет фокус, например: размытие, фокус
- События мыши, срабатывающие, когда пользователь выполняет операцию на странице с помощью мыши, например: dblclick, mouseup
- Событие колеса, срабатывающее при использовании колесика мыши или аналогичного устройства, например: колесико мыши
- Текстовые события, инициируемые при вводе текста в документ, например: textInput
- События клавиатуры, срабатывающие, когда пользователь выполняет операцию на странице с помощью клавиатуры, например: нажатие клавиши, нажатие клавиши
- Событие композиции, инициируемое при вводе символов для IME (редактора метода ввода), например:
- События изменения, запускаемые при изменении базовой структуры DOM, например: DOMsubtreeModified
- В то же время события уровня DOM3 также позволяют пользователям настраивать некоторые события.
2. Модель событий DOM и поток событий
Модель событий DOM делится на захват и всплытие.. Когда происходит событие, оно распространяется между дочерними и родительскими элементами. Это распространение делится на три этапа.
(1) Фаза захвата: фаза, на которой события распространяются от оконного объекта к целевому узлу сверху вниз;
(2) Целевой этап: этап, на котором реальный целевой узел обрабатывает событие;
(3) Стадия всплытия: стадия, на которой события распространяются от целевого узла к оконному объекту снизу вверх.
Конкретный процесс захвата событий DOM
Захват идет сверху вниз, события сначала идут от оконного объекта, затем к документу (объекту), затем к html-тегу (получение html-тега через document.documentElement), затем к тегу body (получение тега body через document.body), затем он передается слой за слоем в соответствии с обычной структурой html и, наконец, достигает целевого элемента.
Процесс всплытия событий — это просто процесс, обратный захвату событий. Далее, давайте рассмотрим пример всплытия событий:
// 例3
<div id="outer">
<div id="inner"></div>
</div>
......
window.onclick = function() {
console.log('window');
};
document.onclick = function() {
console.log('document');
};
document.documentElement.onclick = function() {
console.log('html');
};
document.body.onclick = function() {
console.log('body');
}
outer.onclick = function(ev) {
console.log('outer');
};
inner.onclick = function(ev) {
console.log('inner');
};
Как мы упоминали выше, метод привязки onclick к поведению события элемента выполняется в фазе всплытия (или целевой фазе) поведения события текущего элемента.
3. Прокси события (делегирование события)
Поскольку событие будет распространяться до родительского узла на этапе всплытия, функция прослушивателя дочернего узла может быть определена на родительском узле, а функция прослушивателя родительского узла может единообразно обрабатывать события нескольких дочерних элементов. Такой подход называется делегированием событий.
1. Преимущества
- Сокращение потребления памяти и повышение производительности
Допустим есть список с большим количеством элементов списка, нам нужно отреагировать на событие при клике по каждому элементу списка
// 例4
<ul id="list">
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
......
<li>item n</li>
</ul>
Если вы привяжете функцию к каждому элементу списка, она будет потреблять много памяти и потреблять много производительности с точки зрения эффективности. С помощью прокси-сервера событий нам нужно только привязать методы к родительскому контейнеру ul, чтобы независимо от того, какой элемент-потомок был нажат, поведение щелчка контейнера будет запускаться в соответствии с механизмом передачи пузырькового распространения, а затем будет выполнен соответствующий метод.В зависимости от источника события мы можем знать, кто нажал, и делать разные вещи.
- Динамически связывать события
Во многих случаях нам нужно динамически добавлять или удалять элементы списка с помощью пользовательских операций.Если мы привязываем события к каждому дочернему элементу в начале, то при изменении списка нам нужно повторно привязывать события к вновь добавленным элементам, поэтому что элементы, которые собираются удалить, будут связаны с событиями.Элемент отвязывает событие, если вы используете прокси события, вы избавите себя от таких проблем.
2. Как реализовать
Далее давайте реализуем делегирование события элемента li под родительским элементом #list в приведенном выше примере его родительскому элементу:
// 给父层元素绑定事件
document.getElementById('list').addEventListener('click', function (e) {
// 兼容性处理
var event = e || window.event;
var target = event.target || event.srcElement;
// 判断是否匹配目标元素
if (target.nodeName.toLocaleLowerCase === 'li') {
console.log('the content is: ', target.innerHTML);
}
});
В-четвертых, общее применение объектов Event
- event. preventDefault()
Если этот метод вызывается, поведение события по умолчанию больше не будет срабатывать.. Что такое событие по умолчанию? Например, когда форма нажимает кнопку отправки (отправить), чтобы перейти на страницу, страница тега a по умолчанию перескакивает или точка привязки позиционируется.
Много раз мы используем тег a просто для того, чтобы действовать как обычная кнопка, щелкнуть, чтобы выполнить функцию, не хотим переходить на страницу и не хотим позиционировать привязку.
//方法一:
<a href="javascript:;">链接</a>
Его также можно заблокировать с помощью метода JS и привязать метод к его событию щелчка.Когда мы нажимаем на тег A, сначала будет инициировано событие щелчка, а затем будет выполнено поведение по умолчанию.
//方法二:
<a id="test" href="http://www.cnblogs.com">链接</a>
<script>
test.onclick = function(e){
e = e || window.event;
return false;
}
</script>
//方法三:
<a id="test" href="http://www.cnblogs.com">链接</a>
<script>
test.onclick = function(e){
e = e || window.event;
e.preventDefault();
}
</script>
Далее рассмотрим пример: в поле ввода можно ввести только до шести символов, как этого добиться?
// 例5
<input type="text" id='tempInp'>
<script>
tempInp.onkeydown = function(ev) {
ev = ev || window.event;
let val = this.value.trim() //trim去除字符串首位空格(不兼容)
// this.value=this.value.replace(/^ +| +$/g,'') 兼容写法
let len = val.length
if (len >= 6) {
this.value = val.substr(0, 6);
//阻止默认行为去除特殊按键(DELETE\BACK-SPACE\方向键...)
let code = ev.which || ev.keyCode;
if (!/^(46|8|37|38|39|40)$/.test(code)) {
ev.preventDefault()
}
}
}
</script>
- event.stopPropagation() & event.stopImmediatePropagation()
Метод event.stopPropagation() останавливает передачу события к родительскому элементу, предотвращая выполнение любых обработчиков родительских событий.. Упомянутая выше фаза всплытия событий относится к фазе, в которой события распространяются от целевого узла к оконному объекту снизу вверх.
К событию щелчка внутреннего элемента в примере 4 мы добавляемevent.stopPropagation()
После этого предложения выполнение родительского события блокируется, и в конце печатается только «внутреннее».
inner.onclick = function(ev) {
console.log('inner');
ev.stopPropagation();
};
stopImmediatePropagation останавливает передачу события к родительскому элементу, а также запуск других слушателей того же типа события в элементе. И stopPropagation может добиться только прежнего эффекта. Давайте посмотрим на пример:
<body>
<button id="btn">click me to stop propagation</button>
</body>
......
const btn = document.querySelector('#btn');
btn.addEventListener('click', event => {
console.log('btn click 1');
event.stopImmediatePropagation();
});
btn.addEventListener('click', event => {
console.log('btn click 2');
});
document.body.addEventListener('click', () => {
console.log('body click');
});
// btn click 1
Как показано выше, после использования stopImmediatePropagation при нажатии кнопки не только событие привязки тела не сработает, но и другое событие нажатия кнопки не сработает.
- event.target & event.currentTarget
Честно говоря, разницу между ними нелегко описать словами.Давайте сначала рассмотрим пример:
<div id="a">
<div id="b">
<div id="c">
<div id="d"></div>
</div>
</div>
</div>
<script>
document.getElementById('a').addEventListener('click', function(e) {
console.log(
'target:' + e.target.id + '¤tTarget:' + e.currentTarget.id
)
})
document.getElementById('b').addEventListener('click', function(e) {
console.log(
'target:' + e.target.id + '¤tTarget:' + e.currentTarget.id
)
})
document.getElementById('c').addEventListener('click', function(e) {
console.log(
'target:' + e.target.id + '¤tTarget:' + e.currentTarget.id
)
})
document.getElementById('d').addEventListener('click', function(e) {
console.log(
'target:' + e.target.id + '¤tTarget:' + e.currentTarget.id
)
})
</script>
Когда мы нажимаем на самый внутренний элемент d, он последовательно выводит:
target:d¤tTarget:d
target:d¤tTarget:c
target:d¤tTarget:b
target:d¤tTarget:a
Из вывода мы видим,event.target
указывает на элемент, вызвавший инициирующее событие, иevent.currentTarget
Это элемент, привязанный к событию, только целевой элемент, на который нажали.event.target
будет равноevent.currentTarget
.То есть,event.currentTarget
всегда прослушиватель событий, аevent.target
является реальным отправителем события.