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

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

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

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

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

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

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

【问题讨论】:

标签: javascript namespaces dom-events


【解决方案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
  • 非常好!保存回调函数的引用是个好主意。
  • 是的。我喜欢这个。最干净的
  • 如果您添加一个具有相同签名的事件而不删除先验,您将失去对前一个的引用,该项目将有两个事件,但有一个绑定引用。您需要更好地控制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 中删除其中一个元素,而它仍然存储对事件处理程序的附加引用,则可能会发生这种情况。如果您打算删除该元素,请确保调用元素的“关闭”方法,一切都应该很好。我认为大多数(?)现代(?)垃圾收集器对这个问题是明智的,但肯定有一些(尤其是旧的)浏览器不是。
【解决方案3】:

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

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

【讨论】:

  • 有道理。我非常专注于将事件处理程序与命名空间一起放置,我没有检查 removeEventListener 上的文档。谢谢。
  • 这对事件命名空间有何帮助?你能举例说明如何在window 上命名mouseup 事件,然后只删除那个事件(假设还有其他非命名空间)?
  • 但是如果我没有对要删除EventListener 的函数的引用怎么办?命名空间在 jQuery 中非常方便。
  • @vsync 在下面看到我的答案。
猜你喜欢
  • 2013-06-16
  • 2015-08-28
  • 2011-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-25
  • 1970-01-01
相关资源
最近更新 更多