【问题标题】:Bubbling event from Class inside a Widget?来自小部件内的类的冒泡事件?
【发布时间】:2012-08-26 19:17:03
【问题描述】:

我拼命尝试从我编写的课程中触发一个事件。我在我的 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 中的冒泡成功!
  • 小部件已加载!
  • 活动已发布。

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

【问题讨论】:

    标签: javascript widget yui yui3 event-bubbling


    【解决方案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 会删除大量的样板。

    【讨论】:

      【解决方案2】:

      我无法告诉你为什么当一个普通的 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. 
      }
      

      【讨论】:

        【解决方案3】:

        有趣的问题!

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

        首先,我测试了来自@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/的例子 当我在普通对象 Slide 上执行 this.fire("testEvent"); 时,YUI 在内部调用链中的许多函数并使用事件 type 操作,即 string = "testEvent"(我称之为“类型”,因为在源代码中它总是保存在变量中名称为“类型”)。 我发现事件会像预期的那样冒泡并丰富您的目标(幻灯片的实例)。 然后它会检查 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/)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-07-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-02-26
          • 2011-02-23
          • 1970-01-01
          相关资源
          最近更新 更多