Javascript 如何在Chrome中克隆元素而不触发事件?

Javascript 如何在Chrome中克隆元素而不触发事件?,javascript,jquery,html,google-chrome,Javascript,Jquery,Html,Google Chrome,我正在尝试克隆type=“file”的输入元素。在这个输入元素中有一个onchange事件。在从onchange事件调用的函数中调用clone方法 我遇到的问题是,当我克隆文件上载输入时,onchange事件再次被触发。这只发生在Chrome中,但在IE中可以正常工作 <input type="file" id="fileUpLoad" onchange="doFunction();" /> doFunction = function() { var oldEl = $('

我正在尝试克隆type=“file”的输入元素。在这个输入元素中有一个onchange事件。在从onchange事件调用的函数中调用clone方法

我遇到的问题是,当我克隆文件上载输入时,onchange事件再次被触发。这只发生在Chrome中,但在IE中可以正常工作

<input type="file" id="fileUpLoad" onchange="doFunction();" />

doFunction = function() {
    var oldEl = $('#fileUpLoad');
    var newEl = $(oldEl).clone();
    $(oldEl).attr('id','fileUpLoadOLD');
    $(oldEl).before(newEl);
}
更新:基于@MichaelAngstadt答案的小提琴。但仍在测试中

在ajaxfileuploader.js扩展中,这似乎对我有用:

    var oldElement = jQuery('#' + fileElementId);
    var oldElEvents = oldElement.data("events");
    var newElement = jQuery(oldElement).attr('id', fileId).data("events", null).clone();
    jQuery(oldElement).attr('id', fileElementId).before(newElement);
    jQuery(oldElement).data("events", oldElEvents);
    jQuery(newElement).appendTo(form);

您可以始终将事件保存在临时对象中,并在克隆后重新附加它们,如:

doFunction = function(){
    var oldEl = $('#fileUpLoad');
    var oldElEvents = oldEl.data("events");
    var newEl = $(oldEl).data("events", null).clone();
    $(oldEl).attr('id','fileUpLoadOLD');
    $(oldEl).before(newEl.data("events",oldElEvents));
}

这样,oldEl实际上没有定义要克隆的事件。否则,您将在克隆和DOM的工作方式方面与一些基本功能进行斗争。

您是否尝试过使用
$克隆对象。请改为使用extend

var newEl = $.extend({},oldEl);

问题似乎与
onchange
属性有关。可以在克隆之前删除/重置属性。克隆后,
change
事件再次触发,并导致无限循环

var newEl = oldEl.removeAttr('onchange').clone();
您正在加载jQuery,为什么不使用它的方法呢?如果您使用
onchange
属性来保留事件处理程序,则可以改用事件委派技术

$(document).on('change', '.fileUpLoads', function() {
     $(this).clone().insertBefore(this);
});

基于@undefined(这是有效的)的答案,我建议实际将变更事件作为容器对象上的委托事件。否则,您将得到一个输入(旧输入)在更改时克隆自身,而另一个输入(新输入)不克隆自身

HTML:

(我还将新输入的值重置为null)

注意:这对我来说仍然是火狐崩溃。不是sutre why,但可能是我的FF-在FF崩溃时,更改事件尚未触发(在其他浏览器中)

解释 我认为这里发生的事情是,当您克隆一个元素时,jQuery(默认情况下)不会克隆事件。但是,它会克隆属性。因此,元素上的
onchange
属性被克隆,并在克隆的元素上创建一个更改事件,出于某种原因,该事件被称为触发infinte循环。不确定为什么
.clone()
会触发更改事件

通过对象上的
.on()
附加的事件不会被克隆-因此没有额外的元素,也没有事件。通过使事件成为容器上的委托事件,我们可以避免问题(因为在克隆期间触发更改事件时,新元素还不是页面的一部分,因此不会触发委托事件),但在新对象上仍然具有功能(一旦我们将其插入页面)


如果您想获得两个以上的此类输入,就需要更好地处理ID。

这里不需要任何花哨的东西。如果使用jQuery/javascript而不是在HTML中附加onchange事件,那么clone()将只创建一个副本

HTML:


p.S
文件上传
,真的吗?其中的大写字母L给我带来了一些问题。

可能是因为您还克隆了元素上的事件绑定。在
clone()
calling后尝试解除绑定
clone(false)
将阻止元素的深度复制。请参阅。@pabo我尝试了.clone(false)和.clone(false,false)都没有用:(我不确定我是否可以复制这个问题。我在Chrome 29.0.1547.65中加载了你的小提琴,当我选择一个文件时,它会创建一个新的fileupload元素。这不是预期的行为吗?我也在Chrome中加载了你的小提琴。目前为止,它不起作用(
$未定义
)但如果我将其设置为mto,则会创建一大堆输入-我最终得到24个,控制台日志中会显示一条消息“范围错误:超过最大调用堆栈”一个堆栈转储显示克隆确实触发了更改。如果我在Firefox中尝试fiddle,当我打开“选择文件”对话框时,它会使我的整个浏览器崩溃!我尝试了这个方法,从某种意义上说它是有效的,但我仍然需要保留该事件,只是在克隆过程中不能调用它。其中一个问题是,你可能最终会遇到多个元素同样的ID,
fileUpLoadOLD
@pabo:没错。因此,“如果你想获得两个以上这样的输入,你需要更好地处理ID。”很好,我没有看到。顺便说一句,你的小提琴不会使我的Firefox(OSX 31.0)崩溃。谢谢。我也在运行31.0(Win 8.1)所以不确定那里发生了什么——但很高兴知道它在其他地方起作用:)在我的实际应用程序中尝试一下,看看是否有效,应该做的是克隆fileupload控件,将其附加到iframe中的一个新表单中,重置用于重用克隆的fileupload控件,然后发布iframe以上载该文件。这是一个很好的建议,但我尝试了几种不同的变体但仍然无法将事件返回oldEl进行多个文件上载。这不完全是答案,但非常接近,我基本上在这里使用了您的思维过程,并且能够完成我需要的…至少我认为目前为止。这个答案对我不起作用。显示出与原始()相同的问题。这将删除数据中的事件,但该事件是通过属性设置的,因此在克隆元素时从
onchange
属性创建。如果通过jQuery(即作为数据)设置事件,则无需删除/重新应用它们。
$(document).on('change', '.fileUpLoads', function() {
     $(this).clone().insertBefore(this);
});
<div class="container">
    <input type="file" class="foo" id="fileUpLoad" />
</div>
$(function () {
    $('.container').on('change', '.foo', function () {
        var oldEl = $('#fileUpLoad');
        var newEl = $(oldEl).clone().val('');
        $(oldEl).attr('id', 'fileUpLoadOLD');
        $(oldEl).before(newEl);
    });
});
<input type="file" id="fileUpLoad" />
$(document).ready( function() {
    $('#fileUpLoad').change( function() {
        doFunction();
    });
});

doFunction = function() {
    var oldEl = $('#fileUpLoad');
    var newEl = $(oldEl).clone( );
    $(oldEl).attr('id','fileUpLoadOLD');
    $(oldEl).before(newEl);
}