前言
经想必大家对于JS当中的事件并不陌生了。我们通过html或dom的方式指定某个事件的处理程序,然后当某个特定的场景(如点击、聚焦、输入等)发生时在触发这些处理程序。每当这个时候我就在想能否有办法可以定制一个事件,又或是摆脱特定场景的桎梏,能够自由的触发一个事件。想要实现这些效果就需要跳到另一个角度去看JS当中的事件。
1.JS事件的本质
JS中事件的本质其实就是一个对象,因此不同类型的事件就对应了不同的类,例如click
事件源自 MouseEvent
类,键盘事件源自KeyboardEvent
类,聚焦事件源自FocusEvent
类。而上述的这些类型追本溯源又都继承自Event
类。因此通过Event
类,或者它的派生类,我们就可以自己通过编程的方式创建一个事件。
所有的事件类都接收两个参数:typeArg
和eventinit
。
typeArg
用于指定事件名称eventinit
可选,它是一个用于指定事件的相关信息的集合,这些信息会在 事件处理程序的event
对象中体现出来。注意不同事件类型的eventinit
集合 中所接收的字段不同,请查阅相关文档。
那么此时我就已经可以自己创建一个click
事件:
const myClickEvent = new MouseEvent('click',{ bubbles:true,//是否冒泡 cancelable:true,//是否可取消 clientX:10,//事件触发时鼠标在浏览器窗口中的位置 clientY:20, })
复制
2.事件派发
现在我们已经能够自己创建一个事件,但仅仅如此还不能实现事件模拟,因为我们创建的事件还无法使用。想要使用事件,就要通过EventTarget.dispatchEvent()
方法进行事件派发。
EventTarget
是事件目标类型,它有三个方法addEventListener
、removeEventListener
和dispatchEvent
。所有可能的事件目标,例如 Element
、document
、window
,都会实现这三个方法。
因此我们就可以使用dispatchEvent()
方法将之前创建的click
事件派发给某个元素。
document.getElementById('eventButton').dispatchEvent(myClickEvent)
复制
3.事件模拟
有了上两节的知识,此时我们就可以实现事件模拟了:
<!DOCTYPE html> <html lang="en"> <body> <button id="eventButton">事件按钮</button> <script> const eventButton = document.getElementById('eventButton') // 监听事件 eventButton.addEventListener('click', function (event) { console.log('event', event) console.log('this', this) }) // 创建一个点击事件 const myClickEvent = new MouseEvent('click', { bubbles: true, //是否冒泡 cancelable: true, //是否可取消 clientX: 10, //事件触发时鼠标在浏览器窗口中的位置 clientY: 20, }) // 派发创建的点击事件 eventButton.dispatchEvent(myClickEvent) </script> </body> </html>
复制
上面的代码中,无需点击按钮即可自动触发它的点击事件。
并且事件对象中的clientX
、clientY
属性,正是我们创建点击事件时所设置的值
4.自定义事件
在前面我们实现了模拟事件,那么如果我们不是想模拟一个现有的事件,而是想创建一个自定义的事件又应该如何实现呢?
可以使用Event
类来创建自定义事件。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <style> button { width: 80px; height: 30px; } div { width: 500px; height: 500px; background-color: red; visibility: hidden; } </style> </head> <button onclick="handleClick()">显示元素</button> <div id="element1"></div> <body> <script> const div = document.getElementById('element1') //监听show事件 div.addEventListener('show', (e) => { alert(`元素${e.target.id}显示成功`) }) //创建一个show事件 const myEvent = new Event('show') //当点击按钮时,显示div元素,并触发其show事件 function handleClick() { div.style.visibility = 'visible' div.dispatchEvent(myEvent) } </script> </body> </html>
复制
在上面的代码中我创建了一个自定义的show
事件,当点击按钮时就会显示元素div并触发div的show
事件。
如果想要给事件对象添加自定义的数据,那就可以利用CustomEvent
类型来创建自定义事件。CustomEvent
是专门的自定义事件类型,它的eventinit
参数中有一个字段detail
可以让我们用于传递数据。
const myEvent = new CustomEvent('transfer',{ detail:'机密数据' }) window.addEventListener('transfer',(event)=>{ console.log(event.detail); }) window.dispatchEvent(myEvent)
复制
参考资料
- Event - Web API 接口参考 | MDN
- CustomEvent:CustomEvent() 构造函数 - Web API 接口参考 | MDN
- 创建和触发事件 - 事件参考 | MDN