使用事件侦听器克隆bootstrap元素

时间:2016-07-30 05:20:33

标签: javascript jquery twitter-bootstrap clone

我试图克隆一个bootstrap元素,该元素具有bootstrap提供的数据切换行为:

HTML

weapon

克隆后,我将 div <div class="container"> <button aria-expanded="false" data-target="#collapsible_obj_0" data-toggle="collapse" class="btn btn-link collapsed">click here</button> <div style="height: 0px;" aria-expanded="false" id="collapsible_obj_0" class="collapse"> <span>foo</span> </div> </div> 更改为新的唯一ID,并将按钮的ID更改为新div 即可。

JS

data-target

按钮和div是我克隆的对象容器的子项。

有时这会有效,但有时候我最终会得到一个仍然会扩展并收缩原始div的按钮,即使我检查HTML时,ID看起来也是正确的。

我怀疑复制的事件处理程序可能会硬编码对要扩展和收缩的div的id的引用,这就是为什么只修复DOM元素中的ID并不起作用。但是,这并不能解释为什么有些克隆有效,有些则无法有效。

克隆附加了引导行为的东西的正确方法是什么?

所以,有几个答案指出,只是从我的 var header = objectContainer.clone(true); var counter = this.collapsibleObjCounter++; var collapseId = "collapsible_obj_" + counter; header.find(".collapse").attr("id", collapseId); header.find("button[data-toggle='collapse']").attr("data-target", "#"+collapseId); 调用中删除true将避免复制事件监听器。所以我现在意识到我的问题比我在这里过分简化的问题要复杂一些。我会把它作为一个单独的问题。 (Cloning a Bootstrap element but not all of the event listeners

4 个答案:

答案 0 :(得分:8)

到目前为止,您的代码还可以,只需从true删除clone()即可。

<强>已更新

  

布尔值值指示是否应将事件处理程序与元素一起复制。默认值为 false 。因此,当我们在不传递任何布尔值的情况下调用.clone()方法时,它只是复制元素,而不是复制附加到它的事件处理程序。但是,当我们传递值 true 时,它会复制附加到其上的元素和任何事件处理程序

Bootstrap 正在处理动态对象的事件处理程序,因此您无需在克隆中true

<强> LIKE

如果您使用这种方式处理events动态对象

$(".btn").click(.....); 
// This button was dynamically created and you want a click event for it, 
// but it wont work because at the time of event binding this button wasn't exist at all.

<强> BUT

您需要使用event delegation技术处理动态对象的事件

 $(document).on("click",".btn",function(){ .... });

这将起作用,因为事件处理程序绑定到DOM树之上的元素(在本例中为文档),并且当事件到达源自匹配的元素的元素时将执行选择, 这就是 Bootstrap 对动态对象的作用,如果动态对象需要,也可以这样做。对于此,她的 JSFiddle

此外,您需要将整个collapsible部分包装在div中进行克隆。

  

注意:使用.clone()会产生副作用,即生成具有重复id属性的元素,这些属性应该是唯一的。在可能的情况下,建议避免使用此属性克隆元素或使用类属性作为标识符。

因此,您需要在克隆后更新data-targetdiv id 属性,以便新创建的按钮targets新创建的折叠面板

我正在使用 jQuery

以下是代码代码段

$(function(){
  var target = "collapsible_obj_";
  var i = 1;
  
  $("#button").click(function(){
    $(".parent_colapse:last").clone().insertAfter(".parent_colapse:last");        
    $(".parent_colapse:last > button").attr("data-target", "#"+target+i);
    $(".parent_colapse:last .collapse").attr("id", target+i);
    i++;
  });
  
  $(document).on("click",".button",function(){
     alert();
  });
});
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

<div class="parent_colapse">
<button aria-expanded="false" data-target="#collapsible_obj_0" data-toggle="collapse" class="btn btn-link collapsed">click here</button>

<div style="height: 0px;" aria-expanded="false" id="collapsible_obj_0" class="collapse">
  <span>foo</span>
  <button type="button" class="button">click</button>
</div>
  </div>
<button type="button" id="button">Clone</button>

关于您的问题,您没有显示完整的script,这就是我们无法找到错误的原因。 LIKE 我们不知道objectContainer还是collapsibleObjCounter这是什么?

答案 1 :(得分:1)

克隆时不要复制事件,请删除true标记。

var header = objectContainer.clone();

我的猜测是Bootstrap正在处理动态对象的事件绑定,也用于数据切换,它只需要具有不同的id&amp; s&amp;目标

这里是fiddle

PS:在OP的问题中不知道这个或objectContainer是什么,所以在新的包装器中创建了一个闭包和粘贴结果。

答案 2 :(得分:1)

问题不是由事件监听器本身引起的。问题是Bootstrap的工作原理。对于大多数Bootstrap组件,Bootstrap创建与DOM元素关联的JavaScript对象。 克隆Bootstrap组件时需要注意这个对象。对于collapse元素,Bootstrap会创建Collapse object

JavaScript对象通过jQuery&#39; $.data与DOM元素相关联。 这个就是问题所在。如果您使用jQuery&#39; clone并请求将事件处理程序复制到克隆,那么您还会获得$.data数据集的副本。但是,当数据是对JavaScript对象的引用时,则复制到克隆的是引用。所以原始和克隆引用相同的JavaScript对象,这就是一切都误入歧途的地方。顺便提一句,这对Bootstrap来说并不特殊:任何引用都会遇到这个问题。

您可以做的是对作为Bootstrap组件的克隆元素执行$.removeData。这将强制Bootstrap重新创建JavaScript对象。对于自动注册数据API的组件,这应该是所有需要的。 (collapse会自动注册。)对于自动注册的组件(例如工具提示),您需要调用$.[component]手动重新创建组件。

来自forked a fiddle小提琴的aManHasNoName说明了这一点。唯一的修改是:

  1. 将参数true, true添加到var header = objectContainer.clone();

  2. 修改header.find(".collapse").attr("id", collapseId)以在最后添加.removeData()

答案 3 :(得分:0)

我已经创建了一个代码的JSFiddle。最可能的错误似乎是您使用可能会产生问题的this.collapsibleObjCounter++ 0值。

这是一个有效的JSFiddle。如果您正在尝试这样做,请告诉我。谢谢。

  

https://jsfiddle.net/2fgoywzy/1/

<强> JS

$( document ).ready(function() {
for (i = 1; i < 5; i++) { 
    var objectContainer =  $("#main");
    var header = objectContainer.clone(true);
    var counter = i; // replace this with this.collapsibleObjCounter++
    var collapseId = "collapsible_obj_" + counter;

    header.find(".collapse").attr("id", collapseId);
    header.find("button[data-toggle='collapse']").attr("data-target", "#"+collapseId);
    $(header).appendTo('body');
}
});

<强> HTML

<div id="main">
    <button aria-expanded="false" data-target="#collapsible_obj_0" data-toggle="collapse" class="btn btn-link collapsed">click here</button>

    <div style="height: 0px;" aria-expanded="false" id="collapsible_obj_0" class="collapse">
        <span>foo</span>
    </div>
</div>

如果您在0中的值为this.collapsibleObjCounter++,那么我建议您++this.collapsibleObjCounter。而不是后增量执行预增量