【问题标题】:event binding with .on() for JQueryUI dialogs inside JQueryUI tabs事件绑定与.on() 用于 JQuery UI 选项卡内的 JQuery UI 对话框
【发布时间】:2012-02-01 22:57:29
【问题描述】:

我有一个页面,其中包含单击时在 JQueryUI dialog 中生成的“对话框”类链接。这些对话框是从页面上的其他元素创建的,并且可以包含“add_tab”类的链接,单击时应该会创建一个新的 JQueryUI [tab] (http://jqueryui.com/demos/dialog/)。这些选项卡通过 Ajax 加载其内容并包含相同的结构。这意味着对话框中的“add_tab”链接会创建一个新选项卡,其中包含“对话框”链接,这些链接会生成包含更多“add_tab”链接的对话框,依此类推。

这是基本的 HTML 结构:

<div id="tabs">
  <ul>
    <li><a href="#tabs-1">tab 1</a></li>
  </ul>
  <div id="tabs-1">
    <p>This tab contains a <a href="#popup1" class="dialog" target="_new">popup</a> and a direct link to a <a href="tabs2.htm" class="add_tab">new tab</a>.</p>
    <div id="popup1" style="display:nonee;">This popup contains a link to a <a href="tabs2.htm" class="add_tab" target="_new">new tab</a>.</div>
  </div>

使用 JQuery 1.7 的 .on() method,我无法正确注册出现在已添加选项卡的对话框中的“add_tab”链接的点击处理程序。我设法为新生成的选项卡中的“对话框”链接注册了点击处理程序(以便它们生成一个对话框),但未能为出现在这些对话框中的“add_tab”链接注册点击处理程序。我在http://www.kantl.be/ctb/temp/jquerytest/tabs1.htm 上发布了一个简化的测试版本。以以下场景为例:

  1. http://www.kantl.be/ctb/temp/jquerytest/tabs1.htm 上,单击“弹出”:这将生成一个 JQueryUI 对话框
  2. 在对话框中,单击“新选项卡”:这将生成一个新的 JQueryUI 选项卡
  3. 在新添加的标签为“tabs2.htm”的选项卡中,单击“弹出”:这将生成一个 JQueryUI 对话框
  4. 在对话框中,单击“新选项卡”:这不会生成新的 JQueryUI 选项卡,而是在新窗口中打开目标

    ==> 这说明了此事件处理程序显然是如何为新添加的选项卡中生成的对话框中出现的“add_tab”链接正确注册的

  5. 在标签为“tabs2.htm”的选项卡中,单击“新选项卡”:这将生成一个新的 JQueryUI 选项卡

    ==> 这说明了如何为直接出现在新添加的选项卡内的“add_tab”链接正确注册此事件处理程序

这是我的 javascript 代码:

// these event registrations register clicks on $('a.dialog') and $('a.add_tab') to open new JQueryUI dialogs / tabs
// note: this event registration works for all such links on the original page
$('a.dialog').on('click', function(){
  $($(this).attr('href')).dialog(); 
  return false; 
});
$('a.add_tab').on('click', function(){
  $tabs.tabs( "add", $(this).attr('href'), 'added tab'); 
  $('.ui-dialog-content').each(function(){$(this).dialog('close')}) 
  return false; 
}); 
// tabs: upon creation, register clicks on nested $('a.dialog') and $('a.add_tab') to open new JQueryUI dialogs / tabs 
var $tabs = $( "#tabs" ).tabs({    
  add: function(event, ui) { 
    $tabs.tabs('select', '#' + ui.panel.id); 
    $tabs.tabs($tabs.tabs('option', 'selected')) 
      .on('click', 'a.dialog', function(){ 
        $($(this).attr('href')).dialog(); 
        return false; 
      })
      // this registration doesn't seem to work for <a class="add_tab"> links occurring inside generated JQueryUI dialogs inside added JQueryUI tabs          
      .on('click', 'a.add_tab', function(){ 
        $tabs.tabs( "add", $(this).attr('href'), 'added tab'); 
        return false; 
      }); 
  }
});

了!谁能帮我解决上面代码中的最后一个事件处理程序?非常感谢任何帮助!

【问题讨论】:

    标签: performance jquery-ui jquery


    【解决方案1】:

    事件委托的想法是将事件绑定在页面上固定的上(不是动态创建的)。使用 .on() 方法的选择器参数可以告知应该为哪些元素触发事件处理程序。

    在您的代码中,您以两种方式使用事件绑定,如果您使用 .on() 则事件:

    • 首先您直接绑定现有元素 a.dialog 和 a.add_tab - 这仅适用于 tab1 上的链接,因为它们是执行代码时唯一存在的链接,没有事件在这里委托。

    • 添加选项卡时,您是在选项卡容器 $tabs 上进行事件委托:

      • 用于打开带有$tabs.on('click', 'a.dialog', function(){ ... }) 的对话框的链接 - 这可以按预期工作,因为链接 a.dialog 确实在选项卡容器中。

      • 对于带有$tabs.on('click', 'a.add_tab', function(){ ... }) 的对话框中的链接 - 这不起作用,因为创建对话框时,插件会将&lt;div id="popup2"&gt; 移动到正文的末尾(&lt;/body&gt; 之前)。因此,当您单击对话框中的 a.add_tab 时,它不再是选项卡容器的后代,并且不会发生事件委托。

    我会这样做:

    1. 为避免重复相同的代码,请将事件处理程序声明为变量

    2. 对链接 a.dialog 和 a.add_tab 使用选项卡容器上的事件委托

    3. 在创建新对话框时,对对话框使用事件委托来处理它将包含的 a.add_tab 链接

    代码如下:

    var addTabClickHandler = function(e) {
        $tabs.tabs("add", $(this).attr('href'), 'added tab');
        $('.ui-dialog-content').each(function() {
            $(this).dialog('close')
        })
        return false;
    };
    
    var dialogOpenClickHandler = function(e) {
        $($(this).attr('href'))
            .dialog()
            .on('click', 'a.add_tab', addTabClickHandler);
        return false;
    }
    
    var $tabs = $("#tabs").tabs({
        add: function(event, ui) {
            $tabs
                .tabs('select', '#' + ui.panel.id)
                .tabs($tabs.tabs('option', 'selected'));
        }
    });
    
    $tabs
        .on('click', 'a.dialog', dialogOpenClickHandler)
        .on('click', 'a.add_tab', addTabClickHandler);
    

    【讨论】:

    • 感谢您的意见。实际上,这是我最初的方法,但我想这在性能方面并不能很好地扩展。我的真实应用程序有许多必须为元素注册的事件,这些事件既可以发生在原始页面上,也可以发生在新生成的选项卡内。将所有内容绑定到 body 看起来有点矫枉过正(我注意到 Firefox 的内存显着增加),所以我尝试缩小规模。
    • 此外,我看不出在第一页生成的对话框和添加的选项卡之间的页面结构有任何差异:两者都将它们的目标元素移动到正文。尽管如此,'add_tab' 链接 do 在原始页面上生成的对话框中起作用;我希望这可以在所有选项卡上使用,或者在任何选项卡上都没有。除了绑定到正文之外,您是否还看到了另一种解决方案(例如,可以指定对话框附加到的容器吗?)?
    • 我也不太喜欢委托给 body。我会想点儿事回来找你好吗?
    • 谢谢,迪迪埃。与此同时,我想我已经找到了一种解决方法(尽管我仍然不完全理解为什么会出现问题)。
    • 我提供了一个更好的解决方案,将事件委托限制在选项卡容器和对话框内容 div 中。
    【解决方案2】:

    同时,我想出了一个解决方法,只需在“选项卡”容器上注册一次事件处理程序,并在创建时将对话框附加到“选项卡”容器。因此,我的初始代码可以缩减为:

    // tabs: upon creation, register clicks on nested $('a.dialog') and $('a.add_tab') to open new JQueryUI dialogs / tabs 
    var $tabs = $( "#tabs" ).tabs({
      create: function(event, ui) {
        $(this)
          .on('click', 'a.dialog', function(){
            // dialog: upon creation, move the dialog to the tab to ensure delegated event registration
            $($(this).attr('href')).dialog().parent('.ui-dialog').appendTo($tabs);
            return false;
          })
          .on('click', 'a.add_tab', function(){
            $tabs.tabs( "add", $(this).attr('href'), $(this).attr('href'));
            $('.ui-dialog-content').dialog('close');
            return false;
          })
      }
    });
    

    【讨论】:

    • 嗯,这实际上只是实现相同目标的另一种方式。无论如何,您仍然不必使用 .on() 进行所有这些调用。只需在 $tabs 容器上执行一次。 .each() 关闭对话框也是双重工作,插件本身将适用于匹配集上的所有元素,只需执行$('.ui-dialog-content').dialog('close');
    • “Didier 的 cmets 帮助我回答了我自己的问题”...所以你实际上是打算在这里接受你自己的答案???
    • 啊,对不起。在发布此之前,我完全错过了您对原始问题所做的编辑。真的,道歉,会解决需要的。
    • 我确实在几小时前移除了身体绑定 ;-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多