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

我正在尝试克隆一个bootstrap元素,它具有bootstrap提供的数据切换行为:

HTML

foo

克隆后,我将divID更改为新的唯一ID,并将按钮的data-target更改为指向新div

JS

  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); 

button和div是我克隆的对象容器的子代。

有时它可以工作,但有时我最终会得到一个仍然扩展和收缩原始div的按钮,即使我检查HTML时,ID看起来是正确的。

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

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

所以,有几个答案指出,只是从我的clone()调用中删除true将避免复制事件监听器。 所以我现在意识到我的问题比我在这里过于简化的问题要复杂一些。 我会把它作为一个单独的问题。 ( 克隆Bootstrap元素但不是所有事件侦听器 )

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

更新

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

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

喜欢

如果您使用这种方式处理动态对象的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. 

您需要使用事件委派技术处理动态对象的事件 。

  $(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(); }); }); 
    

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

 var header = objectContainer.clone(); 

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

这是一个小提琴 。

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

我已经创建了一个代码的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

 

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

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

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

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

我从ManHasNoName的小提琴中汲取了一个小提琴,说明了这一点。 唯一的修改是:

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

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