【问题标题】:Is it possible to dispatch events on regular objects (not DOM ones)? [duplicate]是否可以在常规对象(不是 DOM 对象)上分派事件? [复制]
【发布时间】:2011-10-01 21:13:32
【问题描述】:

我刚刚发现 FileReader 调度事件就像它是一个 DOM 元素一样。是吗?我想知道是否可以创建一个类似于 FileReader 的对象,它在 HTML/XML 结构中没有表示,但可以调度事件?

【问题讨论】:

    标签: javascript events dom filereader dispatch


    【解决方案1】:

    FileReader 有类似addEventHandler 的方法,因为它是defined 来实现EventTarget 接口。 EventTargetDOM Events 规范定义,但您无需成为 DOM 对象即可实现它。 windowXMLHttpRequestFileReader 是实现 EventTarget 的其他浏览器对象模型对象。

    不幸的是,没有简单的方法来搭载浏览器的事件目标的本机实现......您可以尝试通过使用一个作为prototype 属性从浏览器对象继承,但这通常非常不可靠。不过用纯 JavaScript 自己编写代码来实现所有方法并不难:

    function CustomEventTarget() { this._init(); }
    
    CustomEventTarget.prototype._init= function() {
        this._registrations= {};
    };
    CustomEventTarget.prototype._getListeners= function(type, useCapture) {
        var captype= (useCapture? '1' : '0')+type;
        if (!(captype in this._registrations))
            this._registrations[captype]= [];
        return this._registrations[captype];
    };
    
    CustomEventTarget.prototype.addEventListener= function(type, listener, useCapture) {
        var listeners= this._getListeners(type, useCapture);
        var ix= listeners.indexOf(listener);
        if (ix===-1)
            listeners.push(listener);
    };
    
    CustomEventTarget.prototype.removeEventListener= function(type, listener, useCapture) {
        var listeners= this._getListeners(type, useCapture);
        var ix= listeners.indexOf(listener);
        if (ix!==-1)
            listeners.splice(ix, 1);
    };
    
    CustomEventTarget.prototype.dispatchEvent= function(evt) {
        var listeners= this._getListeners(evt.type, false).slice();
        for (var i= 0; i<listeners.length; i++)
            listeners[i].call(this, evt);
        return !evt.defaultPrevented;
    };
    

    注意:上面的代码在我脑海中浮现,未经测试,但可能有效。但是,它有一些限制,例如如果 Event 对象支持 DOM Level 3 defaultPrevented 属性,则仅支持 dispatchEvent 返回值,并且不支持 DOM Level 3 stopImmediatePropagation()(除非您依赖于您的为它公开属性的自己的事件对象)。也没有层次结构或捕获/冒泡的实现。

    因此,IMO:尝试编写参与 DOM 事件模型的代码不会有太多收获。对于纯 JS 回调工作,我将使用您自己的侦听器列表的临时实现。

    【讨论】:

    • 我有自己的事件模型 - 一个将处理程序绑定到“事件类型”的函数,将它们存储在散列中,以及一个在继承此模型的对象上触发“事件”的函数(以及一些其他实用方法)。你是说默认事件模型比我的没有任何有价值的好处吗?
    • 是的,我想说的好处是很小的——由于无法可靠地读取preventDefault/@ 987654342@/stopImmediatePropagation 已被调用。所以唯一的好处是熟悉 DOM 事件接口......但可以说它是一个相当笨重的接口。
    • 我偶然发现了这个:w3.org/TR/DOM-Level-3-Events/#interface-CustomEvent,W3C 建议将它用于创建特定于应用程序的事件类型。据我所知,尚未得到广泛支持,但似乎这就是整个事情的发展方向。
    • 是的,虽然目前只有 Opera 支持。而且它并没有真正给你那么多,只有一个detail 属性,这在Java 等更严格的语言中很方便,但在JS 中用途有限,你可以在你的对象上放置任意属性。
    • 嗨@bobince。本机事件处理程序与我见过的每个实现(包括我自己的)都使用的此方法之间的区别在于,本机处理程序在与调度程序不同的执行上下文中运行。而使用此方法,一个处理程序中的故障将阻止所有后续处理程序运行。 This post from 2009 让我想到了它,尽管我认为提议的“混合”解决方案对于一般用途来说可能有点重量级。以为你会觉得这很有趣。
    【解决方案2】:

    bobince has the right idea,但他的代码只是一个例子。对于实际经过实战测试的实现,Mr. Doob has one that he uses in three.js

    【讨论】:

    • 如果您不关心模拟 ECMAScript API,也可以考虑 signalsbacon
    【解决方案3】:

    jQuery 可以从常规对象调度事件。 Here's a fiddle.

    function MyClass() {
        $(this).on("MyEvent", function(event) {
            console.log(event);
        });
    
        $(this).trigger("MyEvent");
    }
    
    var instance = new MyClass();
    

    【讨论】:

      【解决方案4】:

      我假设它是 javascript ;通常,任何可以获得对 DOM 元素的引用的对象都应该能够使用 element.dispatchEvent 函数调度事件;见:

      https://developer.mozilla.org/en/DOM/document.createEvent

      https://developer.mozilla.org/en/DOM/element.dispatchEvent

      【讨论】:

      • 是的,来自这些页面。我的意思是 FileReader 似乎与任何 DOM 元素无关,或者对它有引用。但同时它本身有一个 dispatchEvent 方法,可以调度事件(我猜是 DOM 事件)。是不是有点混乱?我想知道是否有办法创建具有相似属性的对象。
      • 好吧,我手头没有任何 FileReader 的实现,所以这只是推测,但如果 DOM 元素只是作为私有方法在内部保存,并且 FileReader 的 dispatchEvent 只是转发调用内部DOM元素的dispatchEvent,我们怎么知道?
      • 内部 DOM 元素是什么意思?现实世界中是否存在这样的术语,或者您是否又在猜测? :) 我猜如果有任何内部 DOM 元素,那么 FileReader 就不需要转发任何东西。它本身可能就是那个。
      • 哦,当然,我不知道 FileReader,因为我猜它是浏览器的一部分,它可以以任何方式实现。我只是在想:如果你想拥有一个具有相同界面和明显行为的自定义类,你所要做的就是让你的对象的私有属性成为一个 DOM 元素(这就是我所说的' internal'),并使用它来调度元素(减去调度事件的 currentTarget 属性的一些潜在问题)。
      猜你喜欢
      • 2016-11-28
      • 2012-05-13
      • 2018-04-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-03
      相关资源
      最近更新 更多