当前位置: 首页 > 科技观察

系统理解浏览器的事件机制

时间:2023-03-19 19:11:46 科技观察

事件流早期IE和Netscape团队在开发第四代浏览器的时候遇到了一个问题:当一个按钮被点击时,是否应该先处理父级的事件?还是应该先处理按钮事件?IE和Netscape给出了两个完全相反的答案。IE提出了事件冒泡的概念,而Netscape则支持事件捕获。事件冒泡事件冒泡认为事件应该由最具体的元素触发,然后逐层传播到父级:事件捕获和事件捕获是相反的,认为最外层的元素应该先接收到事件,然后再去逐层下发:DOM事件流为了兼容浏览器中的两种事件流,DOM2Events规范中将事件流分为三个阶段:事件捕获阶段、底层目标阶段、事件冒泡阶段。可以通过指定addEventListener的第三个参数为true在捕获阶段调用事件处理器来设置事件,默认为false在冒泡阶段调用事件处理器。所有现代浏览器都支持DOM事件流,只有IE8和更早版本不支持。事件处理程序HTML事件处理程序是将事件处理程序直接绑定到HTML属性上://方法一

方法二
HTML事件处理器修改事件比较麻烦,可能需要同时修改HTML和JS,所以大家不喜欢用这个绑定事件的方法。DOM0事件处理程序为DOM元素的事件处理程序属性分配一个函数,例如onclick:letbtn=document.getElementById('div')//addeventbtn.onclick=function(){}//removeeventbtn。onclick=nullDOM2事件处理程序可以通过addEventListener添加DOM2级别的事件处理程序,它接收3个参数:事件名称、事件处理程序和useCapture(可选参数,为布尔值,默认为false表示调用事件处理程序在冒泡阶段)letbtn=document.getElementById('div')btn.addEventListener('click',()=>{},false)和DOM0事件处理器的区别:addEventListener可以改变事件流程,即事件在捕获阶段,但DOM0是不可接受的;addEventListener可以为同一个元素多次添加相同类型的事件处理器,先添加的事件处理器先被触发,如果DOM0为同一个元素绑定了多个相同类型的事件处理器,后面添加的会覆盖掉较早定义的;它有几个注意事项:如果在捕获阶段不需要拦截,useCapture,即第三个参数可以不传;通过addEventListenerHandlers添加的事件只能通过removeEventListener移除,绑定的事件handler必须相同。letbtn=document.getElementById('div')lethandler=function(){}btn.addEventListener("click",handler)btn.removeEventListener("click",handler)事件处理器不兼容IE8及更早版本,因为addEventListener,所以此时可以使用attachEvent添加事件处理器,使用detachEvent移除事件处理器。letbtn=document.getElementById('div')btn.attachEvent("onclick",function(){})有几个注意事项:注册的事件名和DOM0一样,需要on,比如onclick;通过attachEvent添加的事件处理程序的内部this将指向window,而DOM0和DOM2的this将指向元素本身;和addEventListener一样,attachEvent也可以为同一个元素多次添加同一个事件类型的handler,但是触发顺序定义在后面Triggerfirst;通过detachEvent移除事件处理程序时,处理程序必须与注册的相同,与addEventListener保持一致;attachEvent和detachEvent是IE特有的API,所以如果有兼容性需求,我们可以写跨浏览器的事件处理器:varEventUtil={addHandler:function(element,type,handler){if(element.addEventListener){element.addEventListener(type,handler,false)}elseif(element.attachEvent){element.attachEvent("on"+type,handler)}else{element["on"+type]=handler;}},removeHandler:function(element,类型,处理程序){if(element.removeEventListener){element.removeEventListener(类型,处理程序,false)}elseif(element.detachEvent){element.detachEvent(“on”+type,handler)}else{element[“on”+type]=null}}}事件对象由不同的事件处理器event添加,事件对象的一个??属性它们略有不同,我们不需要记住它们的区别,我们只需要在写代码的时候养成编写兼容代码的习惯,下面是一个兼容各种事件对象的事件处理器:lethandler=function(event){//eventobjectletevent=event||window.event//目标元素lettarget=event.target||event.srcElement//防止默认事件触发if(event.preventDefault){event.preventDefault()}else{event.returnValue=false}//防止事件冒泡if(event.stopPropagation){event.stopPropagation()}else{event.cancelBubble=true}}事件类型DOM3Events定义了以下事件类型:UIEvent:涉及与BOM交互的常见浏览器事件,如onload、resize、scroll、input、select等;FocusEvent:当元素获得和失去焦点时触发,例如focus、blur;鼠标事件(MouseEvent):当鼠标在页面上执行某些操作时使用触发,例如click、mousedown、mouseover等;滚轮事件(WheelEvent):当鼠标滚轮(或类似设备)被使用时触发,例如mousewheel;输入事件(InputEvent):在文档中输入文本时触发,如textInput;键盘事件(KeyboardEvent):当使用键盘在页面上执行某些操作时触发,如keydown、keypress;组合事件(CompositionEvent):当使用某种输入法(InputMethodEditor,输入法编辑器)输入字符时触发,例如组合开始事件委托事件委托是指将绑定到多个元素的事件传递给它们共同的父元素进行绑定事件冒泡原理,从而在一定程度上优化性能有些人也喜欢称其为事件代理。例如,在Vue中,事件通常绑定到每个列表项:其实更好的方法是使用事件委托,给ul绑定事件:{{item}}handleClick(event){lettarget=event.targetif(target==='li'){letdata=target.dataset.item}}谢谢首先,感谢您阅读本文,我相信您的时间是值得的。