JavaScript - 事件
参考:https://www.cnblogs.com/st-leslie/p/5907556.html
https://segmentfault.com/a/1190000013265547?utm_source=tag-newest#articleHeader0
事件
HTML与JavaScript交互是通过事件驱动来实现的,例如鼠标点击事件、页面的滚动事件onscroll等等,可以向文档或者文档中的元素添加事件侦听器来预订事件。
1、事件流
事件流,事件触发的顺序。
IE提出冒泡流,网景提出捕获流。
JS事件流原理图:
事件流过程: 捕获过程(1~5) -> 目标过程(5~6) -> 冒泡过程(6~7);
始于window,终于window的过程。
事件捕获:当某个元素触发某个事件(如onclick),顶层对象document就会发出一个事件流,随着DOM树的节点向目标元素节点流去,直到到达事件真正发生的目标元素。在这个过程中,事件相应的监听函数是不会被触发的。
事件目标:当到达目标元素之后,执行目标元素该事件相应的处理函数。如果没有绑定监听函数,那就不执行。
事件冒泡:从目标元素开始,往顶层元素传播。途中如果有节点绑定了相应的事件处理函数,这些函数都会被一次触发。
(1)冒泡流
特征:自底向上
(2)捕获流
特征:自顶而下
2、事件级别
DOM级别与DOM事件关系图:
事件级别支持情况:
(1)DOM0 (HTML事件)
它是写在html里面的,是全局作用域:
例:
<div onclick="alert('1')"></div>
(2)DOM2(属性事件)
一个元素只能绑定一个事件,且最后面绑定的事件会覆盖前面的内容。
例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>事件级别 - DOM2</title> <script> window.onload = function(){ var btn1=document.getElementById("btn1"); var content=document.getElementById("content"); btn1.onclick=function(){ alert("btn1_click"); } btn1.onclick=function(){ alert("btn1_click2"); } content.onclick=function(){ alert("content_click"); } }; </script> </head> <body> <div id="content"> <p>content</p> <button id="btn1">btn1</button> </div> </body> </html>
此时,会先弹出btn1_click2,后弹出content_click。btn1_click这个事件没有被触发,但事件冒泡依然存在。
解除事件绑定: btn1.onclick=null;
游览器兼容性:支持所有游览器
(3)DOM3(事件监听)
一个元素可以绑定多个事件,并按事件添加顺序先后执行。
例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>事件级别 - DOM3</title> <script> window.onload = function(){ var btn1=document.getElementById("btn1"); var content=document.getElementById("content"); btn1.addEventListener("click",function(){ alert("btn1"); },false); btn1.addEventListener("click",function(){ alert("btn2"); },false); content.addEventListener("click",function(){ alert("content"); },false); }; </script> </head> <body> <div id="content"> <p>content</p> <button id="btn1">btn1</button> </div> </body> </html>
运行结果:先弹出 btn1, 然后btn2,最后content;
1)游览器兼容性:
- IE游览器:绑定事件是 attachEvent,解除绑定是 detachEvent
- 标准游览器:绑定事件是 addEventListener,解除绑定是 removeEventListener
代码兼容性写法:
var EventUtil = {
// 绑定事件 addHandler: function (element, type, handler) { if (element.addEventListener) { // 标准游览器 element.addEventListener(type, handler, false); } else if (element.attachEvent) { // IE游览器 element.attachEvent("on" + type, handler); } else { element["on" + type] = handler; } },
// 移除事件 removeHandler: function (element, type, handler) { if (element.removeEventListener()) { // 标准游览器 element.removeEventListener(type, handler, false); } else if (element.detachEvent) { // IE游览器 element.detachEvent("on" + type, handler); } else { element["on" + type] = null; } } };
2)addEventListener
语法:element.addEventListener(event, function, useCapture);
参数说明:
event,事件类型(如 "click" 或 "mousedown")
function,事件触发后调用的函数
useCapture,可选参数,布尔值,描述事件是冒泡还是捕获
3、事件对象(Event)
事件对象,是用来记录一些事件发生时的相关信息的对象。
(1)生命周期
随事件发生时产生,所有事件处理函数运行结束而被销毁
(2)对象属性
1)type属性
通过type我们可以获取事件发生的类型
2)target属性
target属性主要用于获取事件的目标对象
3)鼠标事件属性
在用鼠标触发事件时,主要的事件属性包含鼠标的位置和按键的状态
4)键盘事件属性
在用键盘触发事件时,主要的事件属性包含键盘的按键keyCode和是否按下特殊键
还有很多。。。
(3)对象方法
1)阻止事件冒泡
标准游览器:stopPropagation();
function getEvent(event) { event.stopPropagation(); } child.addEventListener('click', getEvent, false);
IE游览器:event.cancelBubble=true
兼容写法如下:
function getEvent(event) { event = event || window.event; if (event.stopPropagation) { event.stopPropagation(); } else { event.cancelBubble = true; } }
2) 阻止标签默认行为
标准游览器:preventDefault();
例:
<a id="go" href="https://www.baidu.com/">禁止跳转</a> var go = document.getElementById('go'); function goFn(event) { event.preventDefault(); console.log('我没有跳转!'); } go.addEventListener('click', goFn, false);
IE游览器:event.returnValue=false
兼容写法如下:
function goFn(event) { event = event || window.event; if (event.preventDefault) { event.preventDefault(); } else { event.returnValue = false; } console.log('我没有跳转!'); }
3)stopImmediatePropagation
stopImmediatePropagation()在阻止事件冒泡的同时,也把这个元素绑定的同类型事件也阻止了。
<a id="go" href="https://www.baidu.com/">禁止跳转</a>
var go = document.getElementById('go');
function goFn(event) {
const event = event || window.event; event.preventDefault(); event.stopImmediatePropagation(); // 阻止事件冒泡并阻止同类型事件 console.log('我没有跳转!'); }
function goFn2(event) { console.log('我是同类型事件!'); }
go.addEventListener('click', goFn, false); go.addEventListener('click', goFn2, false);
部分游览器不支持;
jQuery此类库库封装了跨平台的stopImmediatePropagation方法。
(4)对象兼容性
在IE8及以前本版之中,通过设置属性注册事件处理程序时,调用的时候并未传递事件对象,需要通过全局对象window.event来获取。解决方法如下:
function getEvent(event) { event = event || window.event; }
4、事件委托
事件委托,就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。
无需遍历所有子节点。
例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>事件委托</title> <script> window.onload = function(){ var btnAdd = document.getElementById('btnAdd'); var ulList = document.getElementById('ulList'); var num = 3; ulList.onclick = function(event){ var event = event || window.event; var target = event.target || event.srcElement; if(target.nodeName.toLowerCase() == 'li'){ alert(target.innerHTML); } } btnAdd.onclick = function () { num++; var li = document.createElement('li'); li.innerHTML = num; ulList.appendChild(li); doclick(); } }; </script> </head> <body> <button id="btnAdd">添加</button> <ul id="ulList"> <li>1</li> <li>2</li> <li>3</li> </ul> </body> </html>
这里用父级ul做事件处理,当li被点击时,由于冒泡原理,事件就会冒泡到ul上,因为ul上有点击事件,所以事件就会触发,当然,这里当点击ul的时候,也是会触发的,所以要判断点击的对象到底是不是li标签元素。
适合用事件委托的事件:click,mousedown,mouseup,keydown,keyup,keypress。