你如何监听两个异步的附加事件处理程序?

时间:2014-06-20 22:17:45

标签: jquery twitter-bootstrap events jquery-deferred

我正在尝试收听两个javascript事件。两者都需要发生,但我不知道它们将以何种顺序发生。在这两种情况发生之前,我不想运行我的代码。我可以将延迟事件与jQuery的事件处理程序附加函数一起使用吗?

具体来说,我想等到带有远程加载内容的bootstrap模式完成显示和加载。

单击此超链接显示模式,使用jquery的load方法在超链接中加载页面,并将加载的页面内容插入到模式中。

<a href="http://www.example.com" data-toggle="modal" data-target="#mymodal">Click Here</a>

目标模式:

<div class="modal fade" id="mymodal>
    <div class="modal-dialog">
        <div class="modal-content"></div>
    </div>
</div>

我尝试附加事件侦听器失败,并使用promises知道两个事件何时被触发。我认为这里的问题是承诺告诉我听众是附属的,而不是事件已经解雇。

var loaded = $(".modal").on('loaded.bs.modal', function(evt) {
    console.log("content loaded");
}).promise();
var shown = $(".modal").on('shown.bs.modal', function(evt) {
    console.log("modal visible");
}).promise();

$.when(loaded, shown).done(function(load, show) {
    console.log("content loaded and modal visible");
});
bootply上的

Demo

2 个答案:

答案 0 :(得分:1)

.promise()返回fx队列的延迟承诺。由于您实际上并没有等待fx队列,因此没有理由在此处使用该特定方法。

咨询bootstrap documentation

  

show.bs.modal - 调用show实例方法时会立即触发此事件。如果由单击引起,则单击的元素可用作事件的relatedTarget属性。

     

shown.bs.modal - 当模式对用户可见时将触发此事件(将等待CSS过渡完成)。如果由单击引起,则单击的元素可用作事件的relatedTarget属性。

     

loaded.bs.modal - 当模式使用远程选项加载内容时会触发此事件。

承诺是一次性使用。一旦他们解决了,你需要产生新的承诺。

如果您知道事件将按特定顺序发生,那么依赖该订单通常就足够了。例如,如果订单始终为:

  1. 显示
  2. 装载
  3. 表示
  4. 然后将事件处理程序附加到shown事件就足够了,因为它总是在loaded事件之后发生。


    我对文档的解释是,shown事件将始终在loaded事件之后触发(为什么显示某些内容还没有?),这意味着您可以只听取shown事件,并完全忽略loaded


    由于我不能100%确定实际的行为,因此我会假设为了这篇文章,订单也可以是:

    1. 显示
    2. 表示
    3. 装载
    4. 我已在列表中加入show,因为它是一个始终如一的起点。在 shown事件被解雇之后,您将无法获得loadedshow个事件。这很有用,因为您可以使用它来生成新的延迟。

      $('.modal').on('show.bs.modal', function () {
          var $this,
              data;
          $this = $(this);
          data = $this.data();
          if (data.shownDeferred) {
              //if this modal had been opened before, but never finished
              //showing it should be cancelled
              data.shownDeferred.reject();
          }
          data.shownDeferred = $.Deferred();
          if (data.loadedDeferred) {
              //if this modal had been opened before, but never loaded
              //it should be cancelled
              data.loadedDeferred.reject();
          }
          data.loadedDeferred = $.Deferred();
      
          $.when(data.shownDeferred, data.loadedDeferred).then(function () {
              $this.trigger('yourcustomeventname');
          });
      }).on('loaded.bs.modal', function () {
          var dfd;
          dfd = $(this).data('loadedDeferred');
          if (dfd) {
              dfd.resolve();
          }
      }).on('shown.bs.modal', function () {
          var dfd;
          dfd = $(this).data('shownDeferred');
          if (dfd) {
              dfd.resolve();
          }
      });
      

      通过上述设置,您可以设置模式,以便在loadedshown事件都已完成触发时触发您自己的自定义事件。


      警告我还没有对这些代码进行过任何测试,因此可能有错误

答案 1 :(得分:0)

对于这个问题,Deferreds / Promises是一个破解坚果的大锤。即使事件的顺序未知,整个事情也可以用布尔来解决,而不是承诺。

但是,的事件顺序已知。运行 test ,您可以看到初始&#34;显示&#34;表现与后续的#34;表演不同。这些事件按顺序排列如下:

    第一个节目
  • - &#39;显示&#39;,&#39;已加载&#39;,&#39;显示&#39;
  • 在随后的节目中 - &#39; show&#39;,&#39;显示&#39;

换句话说,loaded是一次性事件,shown可靠地持续。

因此,您只需听取shown

$('.modal').on('shown.bs.modal', function () {
    //Do awesome stuff here
});

如果你想进一步抑制&#34;节目&#34;在模态显示之前,它稍微涉及但不是太糟糕 - 这样的事情可能是:

$('.modal').on('show.bs.modal', function () {
    var $this = $(this),
        data = $this.data('modal');
    if (!data) {
        data = $this.data('modal') = {};
    }
    if(!data.pending) {
        data.pending = true;
        $this.one('shown.bs.modal', function() {
            data.pending = false;
            //Do awesome stuff here
        });
    }
});

稍微考虑一下,这可能会简化。