来自Widget中Class的冒泡事件?

时间:2012-08-26 19:17:04

标签: javascript widget yui yui3 event-bubbling

我拼命地尝试从我写的课上开始一个事件。我在我的YUI Widget中使用这个类,我想让我的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的必备内容。请帮助我,以便更好地理解这个主题。

3 个答案:

答案 0 :(得分:1)

我认为答案在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!");
});

或者在你的Slide类上设置.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会删除大量样板文件。

答案 1 :(得分:0)

我无法告诉你为什么它在普通的JS-Object和Y.Widget必须交互时失败,而它与两个普通的JS-Objects一起工作。

然而,延长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-Attribute - 它将成为您的小部件监听的前缀:

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. 
}

答案 2 :(得分:0)

有趣的问题!

所以我试图深入解决这个问题。

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

但是如果Slide是普通对象(不是从Y.Base扩展)怎么办?我已经从@ brian-j-miller测试了一些例子并且它不起作用。证明:http://jsfiddle.net/pqr7/hQBHH/4/

然后我运行我的萤火虫并逐步进入YUI源。现在我知道它的细节如何运作了!

让我们看看普通对象Slide http://jsfiddle.net/pqr7/hQBHH/4/的示例 当我在普通对象Slide上执行this.fire("testEvent");时,YUI在内部调用链中的许多函数,并使用事件type进行操作,即字符串= "testEvent"(我将其称为“类型”,因为在源代码中代码它总是保存在名为“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_DELIMITER(冒号)

当你从Y.Base扩展Slide时,这就是区别 - firered事件不是一个简单的testEvent而是Slide:testEvent,它会模式化*:testEvent(http:// jsfiddle达网络/ pqr7 / hQBHH / 3 /)