使用jQuery清除<input type='file' />的内容

559

使用jQuery清除控件的值是否可能?我已经尝试了以下方法:

$('#control').attr({ value: '' }); 

但是它没有起作用。

27个回答

532

简单易行:你可以将<form>标签包裹在元素周围,然后在表单上调用reset函数,最后使用.unwrap()去除表单。与此线程中的.clone()解决方案不同的是,你最终得到的仍然是相同的元素(包括在其上设置的自定义属性)。

已在Opera、Firefox、Safari、Chrome和IE6+中测试并可用。它也适用于其他类型的表单元素,但不适用于type="hidden"

window.reset = function(e) {
  e.wrap('<form>').closest('form').get(0).reset();
  e.unwrap();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<form>
  <input id="file" type="file">
  <br>
  <input id="text" type="text" value="Original">
</form>

<button onclick="reset($('#file'))">Reset file</button>
<button onclick="reset($('#text'))">Reset text</button>

JSFiddle

注意:如果您在表单内放置了重置字段的按钮,则必须在事件上调用.preventDefault()以防止<button>触发提交。


编辑

由于未修复的错误,在IE 11中无法正常工作。输入文本(文件名)被清除,但其File列表仍保留。


14
赢家!可以在任何浏览器中使用,避免克隆输入字段。但是如果清除按钮位于表单内,请将reset()重命名为例如reset2(),因为至少在Chrome浏览器中,如果使用reset(),所有字段都会被清除。在清除调用后添加event.preventDefault()以防止提交。方式如下:<button onclick="reset2($('#file'));event.preventDefault()">Reset file</button>。工作示例:http://jsfiddle.net/rPaZQ/23/。 - Timo Kähkönen
1
@Timo,我已将该函数重命名为resetFormElement,并添加了一条注释,建议你在按钮的onclick事件中使用preventDefault() - slipheed
28
问题在于,这至少暂时使得文件无效。(表格不能包含其他表格)。无论它当前是否有效,它随时可能出现问题。 - cHao
6
@cHao,当然,这仅在输入元素实际位于表单中时才成立,但它并不一定要在表单中。 - Ninjakannon
2
最新版的Chrome不喜欢它(get(0)未定义),我不得不像jQuery文档中建议的那样使用.wrap('<form></form>') - PhiLho
显示剩余5条评论

435

简单回答:替换它。

在下面的代码中,我使用replaceWith jQuery方法用它自己的克隆替换控件。如果你有任何绑定到此控件事件的处理程序,我们也需要保留它们。为了做到这一点,我们将true作为clone方法的第一个参数传递进去。

<input type="file" id="control"/>
<button id="clear">Clear</button>
var control = $("#control");

$("#clear").on("click", function () {
    control.replaceWith( control = control.clone( true ) );
});

示例代码: http://jsfiddle.net/jonathansampson/dAQVM/

如果复制时保留事件处理程序存在问题,您可以考虑使用事件委托来从父元素处理此控件上的点击:

$("form").on("focus", "#control", doStuff);

当控件被刷新时,这可以避免需要克隆任何处理程序与元素一起克隆。


1
这种解决方案的烦人之处在于你必须在代码中两次使用该元素,因此如果有人更改了名称,你必须更改代码两次(这很容易被忘记)。 - Casebash
50
你还可以在该字段上使用 .clone() 方法。 $('#clone').replaceWith($(this).clone()); - metric152
10
仍然无法运行。在替换之前需要清除它。因此,在使用.replaceWith()之前需要使用.val()。因此,代码应为control.val('').replaceWith(...)。 - mnsr

113

Jquery旨在为您解决跨浏览器/旧浏览器问题。

我测试过的现代浏览器上可以正常工作:Chromium v25、Firefox v20、Opera v12.14

使用jquery 1.9.1

HTML

<input id="fileopen" type="file" value="" />
<button id="clear">Clear</button>

Jquery

->

jQuery

$("#clear").click(function () {
    $("#fileopen").val("");
});

jsfiddle上,下面的JavaScript解决方案对我在上述浏览器上也有效。

document.getElementById("clear").addEventListener("click", function () {
    document.getElementById("fileopen").value = "";
}, false);
jsfiddle 上,理论上这应该可以工作,但我没有办法测试IE。如果IE的Javascript版本由于微软使用了不同的方式而无法工作,则jquery方法应该能够处理,否则最好向jquery团队指出IE所需的方法。(我看到有人说“这在IE上行不通”,但没有纯javascript演示如何在IE上运行(据说是“安全特性”?),也许也应该向微软报告它是否被视为错误,以便在任何新版本中修复它)。

和另一个答案中提到的一样,关于jquery论坛上的一篇帖子

 if ($.browser.msie) {
      $('#file').replaceWith($('#file').clone());
 } else {
      $('#file').val('');
 }

但是jquery现在已经移除了对浏览器测试的支持,jquery.browser.

这个JavaScript解决方案对我也很有用,它相当于jquery.replaceWith方法的原生版本。

document.getElementById("clear").addEventListener("click", function () {
    var fileopen = document.getElementById("fileopen"),
        clone = fileopen.cloneNode(true);

    fileopen.parentNode.replaceChild(clone, fileopen);
}, false);

jsfiddle 上。

需要注意的重要事情是,cloneNode 方法不会保留关联的事件处理程序。

可以看这个例子。

document.getElementById("fileopen").addEventListener("change", function () {
    alert("change");
}, false);

document.getElementById("clear").addEventListener("click", function () {
    var fileopen = document.getElementById("fileopen"),
        clone = fileopen.cloneNode(true);

    fileopen.parentNode.replaceChild(clone, fileopen);
}, false);

jsfiddle 上。

然而,jquery.clone 提供了这个[*1]

$("#fileopen").change(function () {
    alert("change");
});

$("#clear").click(function () {
    var fileopen = $("#fileopen"),
        clone = fileopen.clone(true);

    fileopen.replaceWith(clone);
});

jsfiddle上:

[*1]如果事件是通过jQuery的方法添加的,那么jQuery可以做到这一点,因为它会在jquery.data中保留一个副本。否则,它就不起作用了,所以这有点像是一种欺骗/变通方法,并且意味着不同方法或库之间不兼容。

document.getElementById("fileopen").addEventListener("change", function () {
    alert("change");
}, false);

$("#clear").click(function () {
    var fileopen = $("#fileopen"),
        clone = fileopen.clone(true);

    fileopen.replaceWith(clone);
});

jsfiddle上。

您无法直接从元素本身获取附加的事件处理程序。

以下是使用纯JavaScript的一般原则,这也是jQuery和所有其他库的基本方法(大致相同)。

(function () {
    var listeners = [];

    function getListeners(node) {
        var length = listeners.length,
            i = 0,
            result = [],
            listener;

        while (i < length) {
            listener = listeners[i];
            if (listener.node === node) {
                result.push(listener);
            }

            i += 1;
        }

        return result;
    }

    function addEventListener(node, type, handler) {
        listeners.push({
            "node": node,
                "type": type,
                "handler": handler
        });

        node.addEventListener(type, handler, false);
    }

    function cloneNode(node, deep, withEvents) {
        var clone = node.cloneNode(deep),
            attached,
            length,
            evt,
            i = 0;

        if (withEvents) {
            attached = getListeners(node);
            if (attached) {
                length = attached.length;
                while (i < length) {
                    evt = attached[i];
                    addEventListener(clone, evt.type, evt.handler);

                    i += 1;
                }
            }
        }

        return clone;
    }

    addEventListener(document.getElementById("fileopen"), "change", function () {
        alert("change");
    });

    addEventListener(document.getElementById("clear"), "click", function () {
        var fileopen = document.getElementById("fileopen"),
            clone = cloneNode(fileopen, true, true);

        fileopen.parentNode.replaceChild(clone, fileopen);
    });
}());

jsfiddle上。

当然,jQuery和其他库都有维护这样一个列表所需的所有其他支持方法,这只是一个演示。


51

出于明显的安全原因,您无法设置文件输入框的值,即使是将其设置为空字符串也不行。

您只需要重置包含该字段的表单即可,或者如果您只想重置包含其他字段的表单中的文件输入框,则可以使用以下代码:

function reset_field (e) {
    e.wrap('<form>').parent('form').trigger('reset');
    e.unwrap();
}​

这里有一个例子:http://jsfiddle.net/v2SZJ/1/


43

1
没问题!值得注意的是,如果您有任何由文件输入更改触发的事件侦听器,则需要在替换输入后重新分配它们。 - JCollerton

20

IE8为了安全起见,使文件上传字段只读。请参阅IE团队博客文章:

历史上,HTML文件上传控件()是许多信息披露漏洞的来源。为解决这些问题,对控件的行为进行了两个更改。

为了阻止那些依靠“窃取”按键来偷偷地诱骗用户将本地文件路径键入控件的攻击,现在文件路径编辑框是只读的。用户必须使用文件浏览对话框显式选择要上传的文件。

此外,Internet区域的“上传文件时包括本地目录路径”URLAction已设置为“禁用”。此更改可防止潜在敏感本地文件系统信息泄漏到Internet。例如,Internet Explorer 8现在仅提交文件名image.png,而不是完整路径C:\ users \ ericlaw \ documents \ secret \ image.png。


18

$("#control").val('') 是你需要的全部!在使用 JQuery 1.11 的 Chrome 上进行了测试。

其他用户也已在 Firefox 上进行了测试。


2
正如这里的许多其他帖子所解释的那样,这并不是跨浏览器友好的。 - Tisch
为了我理解,这在哪些浏览器中失败了? - TheHamstring
1
在Internet Explorer中失败,因为IE >中的输入类型文件是只读的。 - Lucky
5
可在Chrome和Firefox中使用。已经足够了。 - naimul64

13

在这里,我陷入了所有选项中。以下是我制作的一个黑客技巧,它起作用了:

<form>
 <input type="file">
 <button type="reset" id="file_reset" style="display:none">
</form>

您可以使用类似以下的jQuery代码来触发重置:

$('#file_reset').trigger('click');

(jsfiddle: http://jsfiddle.net/eCbd6/)


3
好的,但它将清除整个表单,而不是特定的文件输入。 - Ashish Ratan

8
我最终得到了这个结果:
if($.browser.msie || $.browser.webkit){
  // doesn't work with opera and FF
  $(this).after($(this).clone(true)).remove();  
}else{
  this.setAttribute('type', 'text');
  this.setAttribute('type', 'file'); 
}

可能不是最优雅的解决方案,但就我所知它能够工作。


https://dev59.com/R2sy5IYBdhLWcg3wsQJj - nischayn22
不适用于Chrome 34(Linux)。replaceWith()方法在两个浏览器(Chrome,Firefox)中均可使用。 - Gaurav Sharma
首先我必须注意到,“$.browser已从jquery 1.9中删除”,但是最后两行(将类型属性更改为文本,然后将其设置回文件)有效。此外,我尝试设置$('#control').val('');或在javascript中使用document.getElementById(control).value = '';也可以,并且不知道为什么我们不应该使用这种方法!?最后,我决定同时使用它们。 - QMaster

8
我使用了https://github.com/malsup/form/blob/master/jquery.form.js,该插件有一个名为clearInputs()的函数,此功能跨浏览器、经过充分测试、易于使用,并且还可以处理IE问题和隐藏字段清除(如果需要)。 这可能是一个略长的解决方案来仅清除文件输入,但如果您正在处理跨浏览器的文件上传,则建议使用此解决方案。
使用方法如下:
// 清空所有文件输入框: $("input:file").clearInputs();
// 同时清空隐藏字段: $("input:file").clearInputs(true);
// 清空指定字段: $("#myfilefield1,#myfilefield2").clearInputs();
/** * 清除所选表单元素。 */ $.fn.clearFields = $.fn.clearInputs = function(includeHidden) { var re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden' is not in this list return this.each(function() { var t = this.type, tag = this.tagName.toLowerCase(); if (re.test(t) || tag == 'textarea') { this.value = ''; } else if (t == 'checkbox' || t == 'radio') { this.checked = false; } else if (tag == 'select') { this.selectedIndex = -1; } else if (t == "file") { if (/MSIE/.test(navigator.userAgent)) { $(this).replaceWith($(this).clone(true)); } else { $(this).val(''); } } else if (includeHidden) { // includeHidden 可以是 true,也可以是选择器字符串 // 指定一个特殊测试;例如: // $('#myForm').clearForm('.special:hidden') // 上述代码将清除具有“special”类的隐藏输入。 if ( (includeHidden === true && /hidden/.test(t)) || (typeof includeHidden == 'string' && $(this).is(includeHidden)) ) this.value = ''; } }); };

我不明白为什么这个答案没有更多的赞?! - AlexB
1
@AlexB:因为正如Timo所解释的那样,仅仅为了清除一个文件输入字段而使用过度的方法。 - TheCarver
不知道是否有效,但在FF 45.0.2上已经无法使用了:( - fralbo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接