Vanilla JavaScript 中的事件处理程序命名空间

Posted

技术标签:

【中文标题】Vanilla JavaScript 中的事件处理程序命名空间【英文标题】:Event Handler Namespace in Vanilla JavaScript 【发布时间】:2014-03-16 01:25:33 【问题描述】:

我熟悉 jQuery 事件处理程序中的命名空间。我可以在特定命名空间中添加事件处理程序:

$('#id').on('click.namespace', _handlerFunction);

然后我可以删除该命名空间中的所有事件处理程序:

$('#id').off('.namespace');

这里的好处是我只能删除这个命名空间中的事件,而不是任何应该维护的用户添加/附加事件。

有没有人有任何关于我如何不能使用 jQuery,但获得类似结果的提示?

【问题讨论】:

danml.com/js/events.js 有这样的东西:您可以使用正则表达式进行选择。还可以在 bower 和 microjs 中搜索“事件”以获取更多类似的内容... 相关:Namespaced Custom Events Trigger 【参考方案1】:

对于仍在寻找这个的人,我最终制作了一个助手单例,它为我跟踪函数引用。

class EventHandlerClass 
  constructor() 
    this.functionMap = ;
  

  addEventListener(event, func) 
    this.functionMap[event] = func;
    document.addEventListener(event.split('.')[0], this.functionMap[event]);
  

  removeEventListener(event) 
    document.removeEventListener(event.split('.')[0], this.functionMap[event]);
    delete this.functionMap[event];
  


export const EventHandler = new EventHandlerClass();

然后只需导入 EventHandler 并使用如下:

EventHandler.addEventListener('keydown.doop', () => console.log("Doop"));
EventHandler.addEventListener('keydown.wap', () => console.log("Wap"));
EventHandler.removeEventListener('keydown.doop');
// keydown.wap is still bound

【讨论】:

美丽在于简单 +1 非常好!保存回调函数的引用是个好主意。 是的。我喜欢这个。最干净的 @MaxCore 是的,developer.mozilla.org/en-US/docs/Web/API/Event/Event 如果您添加一个具有相同签名的事件而不删除先验,您将失去对前一个的引用,该项目将有两个事件,但有一个绑定引用。您需要更好地控制functionMap【参考方案2】:

在这个解决方案中,我将 DOM 扩展为具有 onoff 方法,并能够使用事件命名空间:

var events = 
  on(event, cb, opts)
    if( !this.namespaces ) // save the namespaces on the DOM element itself
      this.namespaces = ;

    this.namespaces[event] = cb;
    var options = opts || false;
    
    this.addEventListener(event.split('.')[0], cb, options);
    return this;
  ,
  off(event) 
    this.removeEventListener(event.split('.')[0], this.namespaces[event]);
    delete this.namespaces[event];
    return this;
  


// Extend the DOM with these above custom methods
window.on = Element.prototype.on = events.on;
window.off = Element.prototype.off = events.off;


window
  .on('mousedown.foo', ()=> console.log("namespaced event will be removed after 3s"))
  .on('mousedown.bar', ()=> console.log("event will NOT be removed"))
  .on('mousedown.baz', ()=> console.log("event will fire once"), once: true);

// after 3 seconds remove the event with `foo` namespace
setTimeout(function()
    window.off('mousedown.foo')
, 3000)
Click anywhere 

【讨论】:

我对此表示赞同,但在 DOM 中存储 js 对象引用有一些注意事项,因为如果你不知道自己在做什么,它可能会导致内存泄漏。例如,如果您从 DOM 中删除其中一个元素,而它仍然存储对事件处理程序的附加引用,则可能会发生这种情况。如果您打算删除该元素,请确保调用元素的“关闭”方法,一切都应该很好。我认为大多数(?)现代(?)垃圾收集器对这个问题是明智的,但肯定有一些(尤其是旧的)浏览器不是。 相关:addEventListener-memory-leaks【参考方案3】:

我认为您正在寻找addEventListener 和removeEventListener。您还可以定义自定义事件并使用dispatchEvent 触发它们。

但是,要删除事件侦听器,您需要保留对事件函数的引用,以便仅删除要删除的函数,而不是清除整个事件。

【讨论】:

有道理。我非常专注于将事件处理程序与命名空间一起放置,我没有检查 removeEventListener 上的文档。谢谢。 这对事件命名空间有何帮助?你能举例说明如何在window 上命名mouseup 事件,然后只删除那个事件(假设还有其他非命名空间)? 但是如果我没有对要删除EventListener 的函数的引用怎么办?命名空间在 jQuery 中非常方便。 @vsync 在下面看到我的答案。

以上是关于Vanilla JavaScript 中的事件处理程序命名空间的主要内容,如果未能解决你的问题,请参考以下文章

当弹出窗口关闭时,我将如何引发事件(jQuery 或 vanilla Javascript)?

使用 vanilla JavaScript 在客户端处理 Firebase ID 令牌

es6 vanilla javascript中的Ajax请求

javascript [相同]用于匹配数组#vanilla #script中的两个字符串的脚本

将对象列表打印为 vanilla javascript 中的链接

Vanilla JavaScript:禁用整个网站中的所有关键组合