1

我拼命尝试从我写的课程中触发一个事件。我在我的 YUI 小部件中使用这个类,我希望我的 YUI 小部件响应触发的事件。我知道事件冒泡是如何工作的,所以这里的代码工作得很好:

    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 中冒泡成功!
  • 小部件已加载!
  • 活动发布。

似乎我真的很怀念关于小部件的一些重要内容。请帮助我以便更好地理解这个主题。

4

3 回答 3

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 将删除大量样板文件。

于 2012-08-27T13:18:23.627 回答
0

有趣的问题!

所以我试图更深入地解耦这个问题。

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

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

然后我运行我的 firebug 并一步一步地研究 YUI 源代码。现在我知道它是如何工作的了!

让我们看看普通对象幻灯片http://jsfiddle.net/pqr7/hQBHH/4/的示例 当我this.fire("testEvent");在普通对象幻灯片上做时,YUI 在内部调用了很多链中的函数并使用type字符串 = "testEvent"(I称它为“type”,因为在源代码中它总是保存在名为“type”的变量中)。我发现事件会像预期的那样冒泡并丰富您的目标(幻灯片的实例)。然后它检查 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 时的区别 - 触发的事件并不简单testEvent,但Slide:testEvent它计算了模式*:testEvent(http://jsfiddle.net/pqr7/hQBHH/3/)

于 2012-08-29T09:18:05.107 回答
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. 
}
于 2012-08-26T22:22:40.030 回答