通常经过以下的方法对元素添加监听事件html
target.addEventListener(type, listener[, options]); target.addEventListener(type, listener[, useCapture]);
当第3个参数是object时,能够有下面的参数浏览器
Boolean
值,代表监听函数在捕获阶段触发Boolean
值,代表监听函数在触发一次以后,就会自动从监听事件的列表中移除(至关于removeEventListener)Boolean
值,代表在监听函数内部不会使用 preventDefault()
来取消浏览器的默认行为。即便调用 preventDefault()
也没有任何效果关于 passive
的介绍能够看 这篇文章异步
首先,如今的浏览器基本都支持 冒泡+捕获 的事件流模型,这里就不在多加介绍函数
对事件对象来讲: window
> document
> body
> 父类元素 > 事件目标网站
对注册类型来讲: 内联事件 优先于 经过代码注册的事件(内联事件也就是写在html元素标签属性上的事件,如 <a onclick='...'></a>)spa
对事件触发阶段来讲: 捕获 优先于 冒泡线程
对注册事件的顺序来讲: 先注册的先调用code
经过实际例子检验一下:htm
<div id='div1'> <div id='div2'> <div id='div3'> <button type='button' onclick='console.log("inline onclick")'>Test</button> <p>11111111111111</p> </div> </div> </div>
function x(e){ //用 eventPhase 来检测当前事件的处理阶段 return e.eventPhase==3 ? 'bubbles':'capture ' } window.addEventListener('click',(e)=>{ console.log('window click 0 in '+ x(e),e) }); window.addEventListener('click',(e)=>{ console.log('window click 1 in '+ x(e),e) }); window.addEventListener('click',(e)=>{ console.log('window click 2 in '+ x(e),e) },true); document.addEventListener('click',(e)=>{ console.log('document click in ' + x(e) ,e) }) document.addEventListener('click',(e)=>{ console.log('document click in ' + x(e) ,e) },true) document.querySelector('#div2').addEventListener('click',(e)=>{ console.log('----start------') console.log('event in ' + x(e),e) console.log('target',e.target) console.log('current target',e.currentTarget) console.log('----end------') }) document.querySelector('button').addEventListener('click',(e)=>{ console.log('----start------') console.log('event in ' + x(e),e) console.log('target',e.target) console.log('current target',e.currentTarget) console.log('----end------') },true)
点击按钮,咱们能够看一下控制台是如何输出的对象
通常是使用下方两个方法中断事件流的传播(注意,阻止事件传播不是销毁event对象,event依然会返回给浏览器)
event.stopPropagation() // 阻止event往其余事件目标传播,可是当前事件目标其余的监听函数会依次调用 event.stopImmediatePropagation() // 当即阻止event传播,不会调用其余的监听函数
阻止事件执行浏览器的默认行为(调用以后没法恢复)
event.preventDefault()
有些事件的触发机制是连续性的,好比 click
事件须要 mousedown
和 mouseup
这两个前置事件的触发(鼠标按键按下而后弹起才算是一个完整的点击),若是在mouseup
里用event.preventDefault()
阻止mouseup的默认行为,click
事件也所以没法触发。 相似的有 keypress
须要 keydown
和keyup
,还有其余。
这里有一个简单的应用:好比一个网站使用这样的代码document.addEventListener('copy',(e)=>{e.preventDefault()})
让用户不能复制页面上的内容。 要突破复制限制,通常的解决方法是用 removeEventListener
,但是这里行不通,由于监听函数是一个匿名函数,而你又没法获得这个函数的引用。 替代的方案是window.addEventListener('copy',(e)=>{e.stopImmediatePropagation()})
这里利用了监听函数执行的优先顺序,提早终止了事件的传播,让网站阻止复制的代码没法执行。
Event
接口表明了DOM中全部事件,是全部事件的父类。在DOM中事件的种类很是多(连接),他们的初始化参数也比较复杂,不可能一一列举,这里只介绍几种用代码的方式自动义事件的例子(不推荐使用 document.createEvent的方式构建事件)
event = new Event(typeArg, eventInit);
typeArg
表示这个事件的名称,能够按照本身的需求定义。若是名称定义为浏览器内置事件的名称,这个事件是没有实际效果的,由于这些事件都有属于他们本身的构造函数,如 click
对应 new MouseEvent
。
eventInit
对象有3个参数
Boolean
值,代表事件是否须要冒泡阶段Boolean
值,代表事件是否能够取消Boolean
值,跟 Shadow DOM 有关,暂时不了解做用eventInit
只有3个参数,基本没什么用处,也不能传递数据,因此经过Event
构造函数建立的事件只有简单的通知做用,告诉你有某个事件被触发了,而后就没了。
event = new MouseEvent(typeArg, mouseEventInit);
mouseEventInit 可用的参数比较多,选择几个重要的说明一下
mouseEventInit = { button: 0, // 鼠标事件的按钮,0是左键,1是中键,2是右键 ctrlKey: false, shiftKey: false, altKey: false, // 对应于键盘上的三个控制键是否被按下 screenX: 0, screenY: 0, // 对应事件触发时鼠标在用户屏幕上的坐标 clientX: 0, clientY:0, // 对应事件触发时鼠标在用户浏览器界面上的坐标 }
建立一个鼠标事件能够这样
var event = new MouseEvent('click',{}) // 对,什么都不要,由于参数都有默认值
或者正规一点
var event = new MouseEvent('click', { button: 1, view: window, bubbles: true, cancelable: true });
event = new CustomEvent(typeArg, customEventInit);
CustomEvent顾名思义,就是自定义事件,它可让咱们把数据放在事件对象里面,而且随着事件的传播而传播(终于有一个实用的了),而上面两个事件通常都由浏览器根据用户的行为触发
var event = new CustomEvent('cat', { detail: { // 数据放在 detail 下面,支持任何类型的数据,好比这里的数据类型是一个对象 data: 'balabalalalala', getMySalary: function(){ return 20000; } } });
要建立浏览器自带事件,并用代码来模拟事件的触发,须要选择正确构造函数和正确的构造参数来建立事件。这些参数都在 MDN 上有详细的介绍,想对事件深刻理解的话不妨认真阅读。
我我的了解到的总共有这3种触发方式
这三种方法的触发是相互影响的,并不能彻底独立开来。
“原生”事件如浏览器本身触发事件在执行监听函数时是异步执行的,可是 element.dispatchEvent(event)
是同步执行的,也就是说,dispatchEvent调用后,当前的JS运行线程会阻塞在这里,直到全部的监听函数被执行并结束。
鉴别是浏览器派发的事件仍是经过JS代码的方式手动触发的事件,只需检测 event
里的isTrused
属性,为true
就是浏览器触发的,false
则是代码触发的,这个属性没法用初始化参数进行初始化