使用事件侦听器克隆bootstrap元素
我正在尝试克隆一个bootstrap元素,它具有bootstrap提供的数据切换行为:
HTML
foo
克隆后,我将div的ID
更改为新的唯一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-target
和div
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(); }); });
foo
克隆时不要复制事件,删除true
标志。
var header = objectContainer.clone();
我的猜测是Bootstrap正在处理动态对象的事件绑定,也用于数据切换,它只需要具有不同的id和目标。
这是一个小提琴 。
PS:不知道在OP的问题中这个或objectContainer是什么,所以在新的包装器中创建了一个闭包和粘贴结果。
我已经创建了一个代码的JSFiddle。 最可能的错误似乎是你使用this.collapsibleObjCounter++
值0
可能会产生问题。
这是一个有效的JSFiddle。 如果您正在尝试这样做,请告诉我。 谢谢。
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
foo
如果你在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的小提琴中汲取了一个小提琴,说明了这一点。 唯一的修改是:
-
添加参数
true, true
tovar header = objectContainer.clone();
-
修改
header.find(".collapse").attr("id", collapseId)
以在末尾添加.removeData()
。