小部件内类中的气泡事件

Bubbling event from Class inside a Widget?

本文关键字:气泡 事件 小部      更新时间:2023-09-26

我拼命想从我编写的类中激发一个事件。我在我的YUI小部件中使用这个类,并且我希望我的YUI小部件响应被激发的事件。我知道事件Bubbling是如何工作的,所以这里的代码工作得非常好:

    YUI().use('event-custom', 'node', function (Y) {
function Publisher(bubbleTo) {
        this.addTarget(bubbleTo);
        this.publish("testEvent", {
            emitFacade: true
        });
        this.fire("testEvent");
}
function BubbleTarget() {
    this.on("testEvent", function (e) {Y.log("Bubbling in Test.js succeed!")});
    var newPublisher = new Publisher(this);
}
// To fire events or be a bubble target, augment a class with EventTarget
Y.augment(Publisher, Y.EventTarget);
Y.augment(BubbleTarget, Y.EventTarget);
var bubbleTarget = new BubbleTarget();});

然而,当我试图将这个概念应用于我的Widget时,我很难失败。

YUI.add("SlideShow", function(Y) {
function SlideShow(config) {
    SlideShow.superclass.constructor.apply(this, arguments);
}
SlideShow.NAME = "SlideShow";
Y.extend(SlideShow, Y.Widget, {
    initializer: function() {   
        Y.log("Widget loaded!");
        this.on("testEvent", function () {
                Y.log("This should, but won't appear despite how hard I try!");
          });
    },
    renderUI: function(){
        var testSlide = new Slide("text", this);
    }
});
Y.SlideShow = SlideShow;
function Slide(sendTo)
{
this.addTarget(sendTo);
    this.publish("testEvent", {
        defaultFn: function(){Y.log('Event published.')},
        emitFacade: true
    });
    this.fire("testEvent");
}
Y.augment(Slide,Y.EventTarget, true, null, {emitFacade: true});
}, "0.0.1", {requires:["widget","event-custom","node","anim"]});

Chromium中的日志输出为:

  • 在Test.js中冒泡成功
  • 小工具已加载
  • 事件已发布

我似乎真的很怀念Widgets的一些精髓。请帮我更好地理解这个主题。

我想答案在Mitch的帖子里。您需要在气泡目标订阅上添加事件前缀。因此:

this.on("testEvent", function () {
    Y.log("This should, but won't appear despite how hard I try!");
});

尝试:

this.on("*:testEvent", function () {
    Y.log("This should, but won't appear despite how hard I try!");
});

或者在幻灯片类上设置.NAME(无论如何你都应该这样做):

Slide.NAME = "Slide";

然后你的前缀使用这个值:

this.on("Slide:testEvent", function () {
    Y.log("This should, but won't appear despite how hard I try!");
});

使用Y.Base.create将删除大量样板。

当一个普通的JS对象和一个Y.Widget必须交互时,我无法告诉你为什么它会失败,而它可以与两个普通的JavaScript对象一起工作。

然而,扩展Y.Base将解决您的问题,同时充分利用Y.Base的力量:

function Slide(config)
{
    Slide.superclass.constructor.apply(this, config);
}
Slide.NAME = "slide";
Y.extend(Slide, Y.Base, {
    initializer : function() {
               this.publish("testEvent", {
                  emitFacade: true//you do not need to specify this, 
                                  //it will be set implicitly to true
                                  //when using Y.Base
                });
            },
    test : function(arg) {
        this.addTarget(arg);
        this.fire("testEvent");
    }
});

这里重要的是NAME属性-它将成为小部件要监听的前缀:

Y.extend(SlideShow, Y.Widget, {
    initializer: function() {   
       Y.log("Widget loaded!");
       this.on("slide:testEvent", function () {
            Y.log("This will work!");
        });
       this.on("*:testEvent", function () {
            Y.log("This will work, too no matter what's the Event's prefix!");
        });
       this.on("Slide:testEvent", function () {
              Y.log("This won't work, since the prefix doesn't match the NAME-Attribute!");
        });
    },
    //rendering etc.
});

在renderUI中,您将调用:

renderUI: function(){
    var testSlide = new Slide();
    testSlide.on('testEvent', function(e) {
       Y.log('You can listen for testEvent without a prefix on a Slide-object.');
    });
    testSlide.test(this);//adds this Widget as the target for the testSlide. 
}

有趣的问题!

因此,我试图深入研究并将问题脱钩。

首先,我测试了@Mitch的例子——正如预期的那样,它有效!证明:http://jsfiddle.net/pqr7/hQBHH/3/

但如果Slide是普通对象(不是从Y.Base扩展而来)呢?我测试了@brian-j-miller的例子,但它不起作用。证明:http://jsfiddle.net/pqr7/hQBHH/4/

然后我运行我的firebug并逐步深入YUI源代码。现在我知道它是如何详细工作的!

让我们看看带有普通对象Slide的示例http://jsfiddle.net/pqr7/hQBHH/4/当我在普通对象Slide上执行this.fire("testEvent");时,YUI在内部调用链中的许多函数,并使用字符串="testEvent"的事件type进行操作(我称之为"类型",因为在源代码中,它总是保存在名为"type"的变量上)。我发现事件泡沫和丰富你的目标(SlideShow的实例)如预期。然后它检查SlideShow是否有一些订阅type=="testEvent"的事件?回答:没有!

如果您在SlideShow中订阅为this.on('testEvent', ...),则它实际上存储为字符串type=="SlideShow:testEvent"

如果您在SlideShow中订阅为this.on('*:testEvent', ...),它实际上存储为字符串type=="*:testEvent"

如果您在SlideShow中订阅为this.on('Slide:testEvent', ...),则它实际上存储为字符串type=="Slide:testEvent"

但冒泡的是:简单的type=="testEvent",所以SlideShow实例中没有订阅者。

然后,YUI用*:testEvent检查更复杂的规则。不幸的是,我们的简单字符串testEvent与模式*:testEvent不匹配这是原始代码http://yuilibrary.com/yui/docs/api/files/event-custom_js_event-target.js.html#693

if (type.indexOf(PREFIX_DELIMITER) > -1) { /* make a magic to execute a subscriber */ }

type这是我们的冒泡字符串testEvent,它不包含PREFIX_DELITER(它是冒号)

这就是当你从Y扩展Slide时的区别。Base-firered事件不是简单的testEvent,而是Slide:testEvent,它模拟了模式*:testEvent(http://jsfiddle.net/pqr7/hQBHH/3/)