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


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

HTML

<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 的 DIV 一个新的独特的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);

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

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

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

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

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


10089
2017-07-30 05:20


起源

你能展示你的代码吗? - jonju
@jonju我添加了用于修改克隆的javascript。 - PurpleVermont
上面代码中的objectContainer是什么? - Sanjay Radadiya
是什么 collapsibleObjCounter ?如果你在某个循环中这样做,请提供克隆逻辑的补码代码块。这会很有帮助。谢谢 - Abdul Moiz Khan
我试图创建一个jsfiddle,但我无法让bootstrap的东西正常工作。 objectContainer是一个包含按钮和另一个div的div。 collapsibleObjCounter只是一个计数器,一个全局变量,用于为每个新的折叠目标创建新的ID - PurpleVermont


答案:


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

更新

这个 布尔 value指示是否应将事件处理程序与元素一起复制。默认值是  。所以,当我们打电话给 .clone() 方法没有通过任何 布尔 值,它只是复制元素而不是复制 事件处理程序 附在它上面。但是,当我们传递价值时 真正 ,它复制了元素和任何元素 事件处理程序 附在它上面。

引导 正在处理 事件处理程序 对于动态对象,所以你不需要 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 树(在这种情况下,文档)并将在事件到达源自与选择器匹配的元素的元素时执行, 那是什么 引导 对于动态对象,如果动态对象需要,也会这样做。她是 的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 这就是我们无法找到错误的原因。 喜欢 我们不知道 objectContainer 也不 collapsibleObjCounter 那是什么?


8
2017-08-01 06:55



你能解释你的代码是如何工作的吗?您是否忽略了引导程序内置崩溃行为并直接实现它? - PurpleVermont
不,我不会忽略引导程序的内置行为,引导程序崩溃事件仅在存在时发生 click 上 data-target 节点有 toggle 属性功能,所以我不会忽略我用new修改克隆部分的行为 target。 - M.Tanzil
你正在做什么来修改克隆不同于我正在做的事情 header.find(".collapse").attr("id", collapseId); 和 header.find("button[data-toggle='collapse']").attr("data-target", "#"+collapseId);   我通过检查生成的HTML确认这是有效的。 - PurpleVermont
@PurpleVermont到目前为止你的代码还可以删除 true 从 clone(),关于你的问题,你没有充分展示 script 这就是我们无法找到的原因 bug。 喜欢 我们不知道 objectContainer 也不 collapsibleObjCounter 那是什么?这就是我为您创建独立而简单的解决方案的原因。希望你能理解。 - M.Tanzil
我认为你是正确的,只是删除 true 从 clone() 会解决我看到的问题。如果容器div中有其他事件处理程序我需要按原样克隆怎么办? - PurpleVermont


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

var header = objectContainer.clone();

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

这是一个 小提琴

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


1
2017-08-01 07:11



所以,除了......我发布过度简化的代码,并且容器div中还有其他按钮,我需要复制事件处理程序。有没有什么方法可以克隆 true 标志,然后删除相关的侦听器,以一种会导致引导程序重新添加所需的侦听器? - PurpleVermont
您可以尝试使用DOM在DOM树中的某些位置委派这些事件处理程序 .on(),所以你可能根本不需要复制它们,它也适用于动态节点(通过冒泡)。例如。 $('body').on('click', '.someBtn', someFunc)  这将触发事件处理程序 someFunc 点击 someBtn 即使以后动态添加它也是如此。 - n4m31ess_c0d3r


我已经创建了一个代码的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。代替 后增量 做 预增量


0
2017-08-01 07:06



为什么零值会成为问题?它只是一个字符串的一部分。 (如果你担心的话,我绝对不会重复ID。) - PurpleVermont
我重视是重复ID。所以我在pluncker中展示的并不是你想要的? - Abdul Moiz Khan


问题不是由事件侦听器引起的 在他们自己。问题是Bootstrap的工作原理。对于大多数Bootstrap组件,Bootstrap创建与DOM元素关联的JavaScript对象。 克隆Bootstrap组件时需要注意此对象。 为一个 collapse 元素,Bootstrap创建一个 Collapse 目的

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

你能做的就是表演一个 $.removeData 在作为Bootstrap组件的克隆元素上。这将强制Bootstrap重新创建JavaScript对象。对于自动注册数据API的组件,这应该是所需的全部内容。 (collapse 自动注册。)对于那些做的组件  自动注册(例如工具提示),您需要致电 $.[component] 手动重新创建组件。

我有 分叉小提琴 从 aManHasNoName说明这一点的小提琴。唯一的修改是:

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

  2. 修改 header.find(".collapse").attr("id", collapseId) 加上 .removeData() 最后。


0
2017-08-02 11:10