Очистка <input type = 'file' /> с помощью jQuery - PullRequest
530 голосов
/ 25 июня 2009

Можно ли очистить управляющее значение <input type='file' /> с помощью jQuery? Я пробовал следующее:

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

Но это не работает.

Ответы [ 27 ]

518 голосов
/ 13 ноября 2012

Легко: вы оборачиваете <form> вокруг элемента, вызываете сброс формы, а затем удаляете форму, используя .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

Как отмечает Тимо ниже, если у вас есть кнопки для запуска сброса поля внутри <form>, вы должны вызвать .preventDefault() на событии, чтобы предотвратить запуск <button> отправки.


EDIT

Не работает в IE 11 из-за нефиксированной ошибки. Текст (имя файла) очищается на входе, но его список File остается заполненным.

430 голосов
/ 25 июня 2009

Быстрый ответ: замените его.

В приведенном ниже коде я использую метод 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);

Это предотвращает необходимость клонирования любых обработчиков вместе с элементом при обновлении элемента управления.

107 голосов
/ 16 мая 2013

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

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

Вкл. jsfiddle

Следующее решение javascript также работает для меня в браузерах, упомянутых выше.

document.getElementById("clear").addEventListener("click", function () {
    document.getElementById("fileopen").value = "";
}, false);

Вкл. jsfiddle

У меня нет способа проверить с IE, но теоретически это должно работать. Если IE отличается настолько, что версия Javascript не работает, потому что MS сделала это по-другому, метод jquery должен, на мой взгляд, решить эту проблему за вас, иначе стоило бы указать это команде jquery вместе с метод, который требуется IE. (Я вижу людей, которые говорят «это не сработает в IE», но нет ванильного javascript, чтобы показать, как он работает в IE (предположительно, «функция безопасности»?)), Возможно, сообщите об этом также как об ошибке в MS (если они считать его таковым), чтобы он исправлялся в любом новом выпуске)

Как упоминалось в другом ответе, пост на 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

Вы не можете получить прикрепленный обработчик событий непосредственно от самого элемента.

Вот общий принцип в vanilla 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 и другие библиотеки имеют все другие методы поддержки, необходимые для поддержки такого списка, это просто демонстрация.

48 голосов
/ 19 июня 2013

По понятным причинам безопасности вы не можете установить значение для ввода файла, даже для пустой строки.

Все, что вам нужно сделать, это сбросить форму, где поле или если вы хотите только сбросить ввод файла формы, содержащей другие поля, используйте это:

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

Вот пример: http://jsfiddle.net/v2SZJ/1/

43 голосов
/ 29 апреля 2013

Это работает для меня.

$("#file").replaceWith($("#file").clone());

http://forum.jquery.com/topic/how-to-clear-a-file-input-in-ie

Надеюсь, это поможет.

20 голосов
/ 27 июля 2009

В IE8 они сделали поле загрузки файла доступным только для чтения для безопасности. См. IE блог в блоге :

Исторически HTML Control Upload File () был источником значительного числа уязвимостей раскрытия информации. Для решения этих проблем в поведение элемента управления были внесены два изменения.

Чтобы блокировать атаки, основанные на «краже» нажатий клавиш, чтобы незаметно обмануть пользователя и ввести локальный путь к файлу в элемент управления, поле редактирования «Путь к файлу» теперь доступно только для чтения. Пользователь должен явно выбрать файл для загрузки с помощью диалога просмотра файлов.

Кроме того, для URLAction для параметра «Включить путь к локальному каталогу при загрузке файлов» установлено значение «Отключить» для зоны Интернета. Это изменение предотвращает утечку потенциально важной информации локальной файловой системы в Интернет. Например, вместо того, чтобы указывать полный путь C: \ users \ ericlaw \ documents \ secret \ image.png, Internet Explorer 8 теперь будет отправлять только имя файла image.png.

15 голосов
/ 20 сентября 2015

$("#control").val('') это все, что вам нужно! Протестировано на Chrome с использованием JQuery 1.11

Другие пользователи тоже тестировали в Firefox.

12 голосов
/ 22 января 2014

Я застрял со всеми вариантами здесь. Вот взлом, который я сделал, который работал:

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

и вы можете запустить сброс, используя jQuery с кодом, подобным следующему:

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

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

8 голосов
/ 03 апреля 2013

Я использовал https://github.com/malsup/form/blob/master/jquery.form.js,, который имеет функцию под названием clearInputs(), которая является кросс-браузерной, хорошо протестированной, простой в использовании и обрабатывает также проблемы с IE и очистку скрытых полей при необходимости. Может быть, немного длинное решение, чтобы очистить только ввод файла, но если вы имеете дело с загрузкой файлов из кроссбраузера, то это решение рекомендуется.

Использование просто:

// Clear all file fields:
$("input:file").clearInputs();

// Clear also hidden fields:
$("input:file").clearInputs(true);

// Clear specific fields:
$("#myfilefield1,#myfilefield2").clearInputs();
/**
 * Clears the selected form elements.
 */
$.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 can be the value true, or it can be a selector string
            // indicating a special test; for example:
            //  $('#myForm').clearForm('.special:hidden')
            // the above would clean hidden inputs that have the class of 'special'
            if ( (includeHidden === true && /hidden/.test(t)) ||
                 (typeof includeHidden == 'string' && $(this).is(includeHidden)) )
                this.value = '';
        }
    });
};
8 голосов
/ 14 августа 2012

Я закончил с этим:

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'); 
}

, возможно, не самое элегантное решение, но оно работает, насколько я могу судить.

...