Как определить, когда отменить нажатие на ввод файла? - PullRequest
93 голосов
/ 07 января 2011

Как я могу определить, когда пользователь отменяет ввод файла с помощью ввода файла html?

onChange позволяет мне определять, когда они выбирают файл, но я также хотел бы знать, когда они отменяют (закрывают диалог выбора файла, ничего не выбирая).

Ответы [ 28 ]

2 голосов
/ 18 апреля 2018

Я знаю, что это очень старый вопрос, но на случай, если он кому-нибудь поможет, я обнаружил, что при использовании события onmousemove для обнаружения отмены было необходимо проверить два или более таких события за короткий промежуток времени. Это связано с тем, что браузер генерирует отдельные события onmousemove (Chrome 65) каждый раз, когда курсор перемещается из диалогового окна выбора файла и каждый раз, когда он перемещается из главного окна и обратно. Простой счетчик событий движения мыши в сочетании с коротким таймаутом для сброса счетчика обратно в ноль сработал.

1 голос
/ 04 сентября 2015

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

https://code.google.com/p/chromium/issues/detail?id=2508

В этом сценарии вы можете обнаружить это, обработав событие onChange и проверив свойство files .

1 голос
/ 06 августа 2015

Я вижу, что мой ответ был бы весьма устаревшим, но тем не менее. Я столкнулся с той же проблемой. Итак, вот мое решение. Самый полезный код был взломан KGA. Но это не совсем работает и немного сложно. Но я упростил это.

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

"# appendfile" - какой пользователь нажимает, чтобы добавить новый файл. Hrefs получают фокус событий.

$("#appendfile").one("focusin", function () {
    // no matter - user uploaded file or canceled,
    // appendfile gets focus
    // change doesn't come instantly after focus, so we have to wait for some time
    // wrapper represents an element where a new file input is placed into
    setTimeout(function(){
        if (wrapper.find("input.fileinput").val() != "") {
            // user has uploaded some file
            // add your logic for new file here
        }
        else {
            // user canceled file upload
            // you have to remove a fileinput element from DOM
        }
    }, 900);
});
1 голос
/ 05 декабря 2013

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

Вот что я приду:

$(document).on('click', '#image-field', function(e) {
  $('.submit-button').prop('disabled', true)
})
$(document).on('focus', '#image-field'), function(e) {
  $('.submit-button').prop('disabled', false)
})

#image-field - мой селектор файлов. Когда somenone нажимает на него, я отключаю кнопку отправки формы. Суть в том, что когда диалоговое окно файла закрыто - не важно, выбирают ли они файл или отменяют его - #image-field вернул фокус, поэтому я слушаю это событие.

UPDATE

Я обнаружил, что это не работает в сафари и poltergeist / phantomjs. Примите эту информацию во внимание, если хотите ее реализовать.

1 голос
/ 04 сентября 2014

Сочетая решения Шибое и Алкса, я получил самый надежный код:

var selector = $('<input/>')
   .attr({ /* just for example, use your own attributes */
      "id": "FilesSelector",
      "name": "File",
      "type": "file",
      "contentEditable": "false" /* if you "click" on input via label, this prevents IE7-8 from just setting caret into file input's text filed*/
   })
   .on("click.filesSelector", function () {
      /* do some magic here, e.g. invoke callback for selection begin */
      var cancelled = false; /* need this because .one calls handler once for each event type */
      setTimeout(function () {
         $(document).one("mousemove.filesSelector focusin.filesSelector", function () {
            /* namespace is optional */
            if (selector.val().length === 0 && !cancelled) {
               cancelled = true; /* prevent double cancel */
               /* that's the point of cancel,   */
            }
         });                    
      }, 1); /* 1 is enough as we just need to delay until first available tick */
   })
   .on("change.filesSelector", function () {
      /* do some magic here, e.g. invoke callback for successful selection */
   })
   .appendTo(yourHolder).end(); /* just for example */

Как правило, событие mousemove делает свое дело, но в случае, если пользователь сделал щелчок и чем:

  • отменил диалог открытия файла с помощью клавиши ESC (без перемещения мыши), сделал еще один точный щелчок, чтобы снова открыть диалог файла ...
  • переключил фокус на любое другое приложение, затем вернулся в диалоговое окно открытия файла браузера и закрыл его, а затем снова открыл с помощью клавиши ввода или пробела ...

... мы не получим событие mousemove, поэтому не будет отмены обратного вызова. Кроме того, если пользователь отменяет второе диалоговое окно и делает движение мыши, мы получим 2 отмененных обратных вызова. К счастью, специальное событие jQuery focusIn всплывает до документа в обоих случаях, помогая нам избежать таких ситуаций. Единственное ограничение - блокирование события focusIn.

1 голос
/ 20 декабря 2017

Поле типа file, к сожалению, не реагирует на множество событий (размытие было бы прекрасно).Я вижу много людей, предлагающих change -ориентированные решения, и их понижают.

change действительно работает, но имеет большой недостаток (по сравнению с тем, что мы хотим, чтобы произошло).

При новой загрузке страницы, содержащей поле файла, откройте окно и нажмите «Отмена».Ничего, к сожалению, не меняет .

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

  • Следующая часть формы section#after-image в моем случае скрыта от глаз.Когда мой file field изменяется, отображается кнопка загрузки.При успешной загрузке отображается section#after-image.
  • Если пользователь загружает, открывает диалоговое окно файла, а затем отменяет действие, они никогда не видят кнопку загрузки.
  • Если пользователь выбирает файл, кнопка загрузки отображается.Если они затем откроют диалоговое окно и откажутся, событие change будет вызвано этой отменой, и там я смогу (и буду делать) скрывать кнопку загрузки до тех пор, пока не будет выбран правильный файл.

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

Я попытался изменить значение файлов [0] до того, как поле взаимодействовало с.Это ничего не сделало в отношении обмена.

Так что да, change работает, по крайней мере, так хорошо, как мы собираемся получить.Поле файла защищено по понятным причинам, но к разочарованию благонамеренных разработчиков.

Это не соответствует моей цели, но вы можете onclick загрузить предупреждение (неalert(), потому что это останавливает обработку страницы), и скрыть его, если изменение инициируется и файлы [0] равны нулю.Если изменение не вызвано, div остается в своем состоянии.

1 голос
/ 14 сентября 2017

Мне кажется, что работает следующее (на рабочем столе, в Windows):

var openFile = function (mimeType, fileExtension) {
    var defer = $q.defer();
    var uploadInput = document.createElement("input");
    uploadInput.type = 'file';
    uploadInput.accept = '.' + fileExtension + ',' + mimeType;

    var hasActivated = false;

    var hasChangedBeenCalled = false;
    var hasFocusBeenCalled = false;
    var focusCallback = function () {
        if (hasActivated) {
            hasFocusBeenCalled = true;
            document.removeEventListener('focus', focusCallback, true);
            setTimeout(function () {
                if (!hasChangedBeenCalled) {
                    uploadInput.removeEventListener('change', changedCallback, true);
                    defer.resolve(null);
                }
            }, 300);
        }
    };

    var changedCallback = function () {
        uploadInput.removeEventListener('change', changedCallback, true);
        if (!hasFocusBeenCalled) {
            document.removeEventListener('focus', focusCallback, true);
        }
        hasChangedBeenCalled = true;
        if (uploadInput.files.length === 1) {
            //File picked
            var reader = new FileReader();
            reader.onload = function (e) {
                defer.resolve(e.target.result);
            };
            reader.readAsText(uploadInput.files[0]);
        }
        else {
            defer.resolve(null);
        }
    };
    document.addEventListener('focus', focusCallback, true); //Detect cancel
    uploadInput.addEventListener('change', changedCallback, true); //Detect when a file is picked
    uploadInput.click();
    hasActivated = true;
    return defer.promise;
}

При этом используется angularjs $ q, но при необходимости вы сможете заменить его любой другой платформой обещаний.

Протестировано на IE11, Edge, Chrome, Firefox, но, похоже, не работает на Chrome на планшете Android, так как не запускает событие Focus.

0 голосов
/ 16 ноября 2016

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

По сути, скрыть Continue, Save, Proceed или любую другую кнопку. Затем в JavaScript вы получаете имя файла. Если имя файла не имеет значения, не отображать кнопку Continue. Если оно имеет значение, то покажите кнопку. Это также работает, если они сначала загружают файл, а затем пытаются загрузить другой файл и нажимают кнопку отмены.

Вот код.

HTML:

<div class="container">
<div class="row">
    <input class="file-input" type="file" accept="image/*" name="fileUpload" id="fileUpload" capture="camera">
    <label for="fileUpload" id="file-upload-btn">Capture or Upload Photo</label>
</div>
<div class="row padding-top-two-em">
    <input class="btn btn-success hidden" id="accept-btn" type="submit" value="Accept & Continue"/>
    <button class="btn btn-danger">Back</button>
</div></div>

JavaScript:

$('#fileUpload').change(function () {
    var fileName = $('#fileUpload').val();
    if (fileName != "") {
        $('#file-upload-btn').html(fileName);
        $('#accept-btn').removeClass('hidden').addClass('show');
    } else {
        $('#file-upload-btn').html("Upload File");
        $('#accept-btn').addClass('hidden');
    }
});

CSS:

.file-input {
    width: 0.1px;
    height: 0.1px;
    opacity: 0;
    overflow: hidden;
    position: absolute;
    z-index: -1; 
}

.file-input + label {
    font-size: 1.25em;
    font-weight: normal;
    color: white;
    background-color: blue;
    display: inline-block;
    padding: 5px;
}

.file-input:focus + label,
.file-input + label:hover {
    background-color: red;
}

.file-input + label {
    cursor: pointer;
}

.file-input + label * {
    pointer-events: none;
}

Для CSS многое из этого - сделать сайт и кнопку доступными для всех. Придайте вашей кнопке все, что вам нравится.

0 голосов
/ 24 марта 2013

Существует хакерский способ сделать это (добавить обратные вызовы или разрешить некоторые отложенные / обещанные реализации вместо alert() вызовов):

var result = null;

$('<input type="file" />')
    .on('change', function () {
        result = this.files[0];
        alert('selected!');
    })
    .click();

setTimeout(function () {
    $(document).one('mousemove', function () {
        if (!result) {
            alert('cancelled');
        }
    });
}, 1000);

Как это работает: когда открыто окно выбора файла, документ не получает события указателя мыши. Задержка составляет 1000 мс, чтобы диалоговое окно действительно появилось и заблокировало окно браузера. Проверено в Chrome и Firefox (только для Windows).

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

0 голосов
/ 31 января 2018

// Использование наведения вместо размытия

var fileInput = $("#fileInput");

if (fileInput.is(":hover") { 

    //open
} else {

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...