本文已参与「新人创作礼」活动,一起开启掘金创作之路。
需求背景
在页面开发中,经常需要在一些DOM元素上挂载监听用户的的操作事件,如:鼠标点击、鼠标拖动等等。通常都是使用addEventListener来给元素挂载监听事件,使用removeEventListener取消监听事件。然而,在实际开发中,本人遇到过以下的痛点:
1.无论是挂载还是取消,都需要传入的事件名称和处理函数必须一致,一旦有一个参数传入错误便无法取消监听事件,造成程序错误,有时难以察觉。
2.有的需求需要根据用户的交互操作,切换不同的监听函数,这使得取消监听函数时,也是比较麻烦。
3.监听函数如果使用局部定义的函数或者匿名函数,取消时若是找不到相应的函数,则无法进行取消。
解决方案
解决方案比较简单,可以直接封装一个创建DOM监听事件的函数,同时根据传入的参数,生成对应监听事件的取消函数,在需要取消监听事件的地方调用即可。
技术栈
typeScript
代码
首先,定义创建函数的参数类型:
export interface eventParams {
// 挂载监听事件的元素,可选,不存在时默认挂载在window
el?: Element | Window
// 事件名称,必填
name: string
// 处理函数
listener: EventListener | Function
// addEventListener 第三个参数,描述事件是冒泡还是捕获,可选
options?: boolean | AddEventListenerOptions
}
然后,定义创建函数:
export function createListener({
el = window, // 挂载元素默认为window
name,
listener, // 将处理函数命名为listener,本质上还是指向传入处理函数
options = false
}: eventParams): () => void {
// DOM元素挂载监听事件
el.addEventListener(name, listener, options)
// 生成取消函数,使用了闭包,所以不用担心取消时出错或者找不到,
const removeListener = () => el.removeEventListener(name, listener, options)
// 返回取消函数
return removeListener
}
使用
定义一个全局取消函数,或者在需要调用取消函数的作用域内
let removeEvent = () => {}
在需要的地方挂载监听事件,并将上面定义的取消函数赋值
removeEvent = createListener({
el: dom,
name: 'mousemove',
listener: (event: MouveEvent) => {
// do something
}
})
取消时,直接调用取消函数即可:
removeEvent()