我试图克隆一个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)
答案 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-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();
});
});
<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说明了这一点。唯一的修改是:
将参数true, true
添加到var header = objectContainer.clone();
修改header.find(".collapse").attr("id", collapseId)
以在最后添加.removeData()
。
答案 3 :(得分:0)
我已经创建了一个代码的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 强>
<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
。而不是后增量执行预增量