Відповіді:
Хоча це не пряме рішення, а також погано в тому, що воно (лише наскільки я тестував) працює з onfocus (вимагає досить обмежуючого блокування подій), ви можете досягти цього за допомогою наступного:
document.body.onfocus = function(){ /*rock it*/ }
Що приємно в цьому, це те, що ви можете приєднати / відімкнути його в часі за допомогою події файлу, а також здається, що він справно працює з прихованими входами (певна вигода, якщо ви використовуєте візуальне вирішення для шаленого типу вводу за замовчуванням = ' файл '). Після цього потрібно просто розібратися, чи змінилося значення вводу.
Приклад:
var godzilla = document.getElementById('godzilla')
godzilla.onclick = charge
function charge()
{
document.body.onfocus = roar
console.log('chargin')
}
function roar()
{
if(godzilla.value.length) alert('ROAR! FILES!')
else alert('*empty wheeze*')
document.body.onfocus = null
console.log('depleted')
}
Дивіться це в дії: http://jsfiddle.net/Shiboe/yuK3r/6/
На жаль, це, здається, працює лише у веб-браузерах. Можливо, хтось ще може розібратися у рішеннях firefox / IE
addEventListener("focus",fn,{once: true})
. Однак я не міг змусити його вогонь використати document.body.addEventListener
.. Я не знаю чому. Натомість я отримав такий самий результат window.addEventListener
.
mousemove
події на window.document
на додаток до прослуховування focus
на , window
здається, працює скрізь (по крайней мере в сучасних браузерах, я не дбаю про минуле десятиліття затонулих суден). В основному, будь-яка подія взаємодії може бути використана для цього завдання, яке блокується відкритим діалоговим вікном відкритого файлу.
Ви не можете.
Результат діалогового вікна файлу не піддається оглядачу.
change
подія не розсилається.
change
подія для цього також не надсилається.
Тож я кину капелюх на це питання, оскільки придумав нове рішення. У мене є прогресивна веб-програма, яка дозволяє користувачам робити фотографії та відео та завантажувати їх. Ми використовуємо WebRTC, коли це можливо, але повертаємося до засобу вибору файлів HTML5 для пристроїв з меншою підтримкою * кашель Safari кашель *. Якщо ви спеціально працюєте над мобільним веб-додатком для Android / iOS, який використовує вбудовану камеру для прямого фотографування / фотографії, то це найкраще рішення, з яким я зіткнувся.
Суть цієї проблеми полягає в тому, що коли сторінка завантажується, це file
є null
, але тоді, коли користувач відкриває діалогове вікно і натискає "Скасувати", file
це все ще є null
, отже, воно не "змінилося", тому жодна подія "зміни" не запускається. Для настільних комп'ютерів це не так вже й погано, оскільки більшість інтерфейсів настільних ПК не залежать від того, щоб знати, коли викликається скасування, але мобільний інтерфейс користувача, який створює камеру для зйомки фото / відео, дуже залежить від того, коли буде натиснуто скасування.
Я спочатку використовував document.body.onfocus
подію, щоб виявити, коли користувач повернувся з вибору файлів, і це працювало на більшості пристроїв, але iOS 11.3 зламав його, оскільки ця подія не спрацьовує.
Моє рішення для цього - * здригання * для вимірювання часу процесора, щоб визначити, чи стоїть зараз сторінка на передньому плані чи на задньому плані. На мобільних пристроях час обробки відводиться додатку, який зараз на першому плані. Коли видно камеру, вона вкраде час процесора та знизить функцію браузера. Все, що нам потрібно зробити, - це виміряти, скільки часу обробляється наша сторінка, коли камера запустить наш доступний час різко знизиться. Коли камеру закрито (скасовано чи іншим способом), наявний час у нас зменшиться.
Ми можемо виміряти час роботи процесора, використовуючи setTimeout()
для виклику зворотного виклику в X мілісекундах, а потім виміряти, скільки часу потрібно, щоб насправді викликати його. Веб-переглядач ніколи не викликає його точно через X мілісекунд, але якщо це розумно закрити, ми повинні бути на першому плані. Якщо веб-переглядач знаходиться дуже далеко (на 10 разів повільніше, ніж потрібно), то ми повинні бути у фоновому режимі. Основна реалізація цього виглядає так:
function waitForCameraDismiss() {
const REQUESTED_DELAY_MS = 25;
const ALLOWED_MARGIN_OF_ERROR_MS = 25;
const MAX_REASONABLE_DELAY_MS =
REQUESTED_DELAY_MS + ALLOWED_MARGIN_OF_ERROR_MS;
const MAX_TRIALS_TO_RECORD = 10;
const triggerDelays = [];
let lastTriggerTime = Date.now();
return new Promise((resolve) => {
const evtTimer = () => {
// Add the time since the last run
const now = Date.now();
triggerDelays.push(now - lastTriggerTime);
lastTriggerTime = now;
// Wait until we have enough trials before interpreting them.
if (triggerDelays.length < MAX_TRIALS_TO_RECORD) {
window.setTimeout(evtTimer, REQUESTED_DELAY_MS);
return;
}
// Only maintain the last few event delays as trials so as not
// to penalize a long time in the camera and to avoid exploding
// memory.
if (triggerDelays.length > MAX_TRIALS_TO_RECORD) {
triggerDelays.shift();
}
// Compute the average of all trials. If it is outside the
// acceptable margin of error, then the user must have the
// camera open. If it is within the margin of error, then the
// user must have dismissed the camera and returned to the page.
const averageDelay =
triggerDelays.reduce((l, r) => l + r) / triggerDelays.length
if (averageDelay < MAX_REASONABLE_DELAY_MS) {
// Beyond any reasonable doubt, the user has returned from the
// camera
resolve();
} else {
// Probably not returned from camera, run another trial.
window.setTimeout(evtTimer, REQUESTED_DELAY_MS);
}
};
window.setTimeout(evtTimer, REQUESTED_DELAY_MS);
});
}
Я тестував це на останній версії iOS та Android, піднімаючи нативну камеру, встановлюючи атрибути на <input />
елементі.
<input type="file" accept="image/*" capture="camera" />
<input type="file" accept="video/*" capture="camcorder" />
Це виходить насправді набагато краще, ніж я очікував. Він проводить 10 випробувань, вимагаючи викликати таймер за 25 мілісекунд. Потім він вимірює, скільки часу насправді потрібно для виклику, і якщо в середньому 10 випробувань менше 50 мілісекунд, ми припускаємо, що ми повинні бути на передньому плані, а камера зникла. Якщо вона більша за 50 мілісекунд, то ми все одно повинні знаходитись у фоновому режимі і продовжувати чекати.
Я setTimeout()
скоріше використовував, а не setInterval()
тому, що останні можуть чергати кілька викликів, які виконуються відразу один за одним. Це може різко збільшити шум у наших даних, тому я затримався, setTimeout()
хоча це зробити трохи складніше.
Ці конкретні номери спрацювали для мене добре, хоча я принаймні один раз бачив випадки, коли відключення камери було виявлено передчасно. Я вважаю, що це тому, що камера може повільно відкриватися, і пристрій може провести 10 випробувань, перш ніж вона фактично стане фоновою. Додавання нових випробувань або очікування приблизно 25-50 мілісекунд до запуску цієї функції може бути вирішенням цієї проблеми.
На жаль, це не дуже працює для настільних браузерів. Теоретично такий же трюк можливий, коли вони надають пріоритет поточній сторінці перед фоновими сторінками. Однак у багатьох настільних комп'ютерів є достатньо ресурсів, щоб сторінка працювала на повній швидкості навіть у фоновому режимі, тому ця стратегія насправді не працює на практиці.
Одне альтернативне рішення, яке багато хто згадує, що я досліджувало, насміхається над FileList
. Ми починаємо з null
цього <input />
пункту, а потім, якщо користувач відкриє камеру і скасує, вони повернуться null
, що не є зміною і жодна подія не спровокує. Одним із варіантів рішення було б призначити фіктивний файл для початку <input />
сторінки, тому встановлення null
буде змін, що призведе до відповідної події.
На жаль, немає ніякого способу офіційного способу створити FileList
, і <input />
елемент вимагає , FileList
зокрема , і не буде приймати будь-яке інше значення , крім null
. Звичайно, FileList
об'єкти не можуть бути безпосередньо побудовані, як це стосується старої проблеми безпеки, яка, мабуть, вже не актуальна. Єдиний спосіб домогтися одного за межами <input />
елемента - це використовувати хак, який копіює вставки даних, щоб підробити подію буфера обміну, яка може містити FileList
об'єкт (ви, в основному, підробляєте файл перетягування та перетягування -подія на веб-сайті). Це можливо в Firefox, але не для iOS Safari, тому це не було життєздатним для мого конкретного випадку використання.
Потрібно говорити, що це очевидно смішно. Те, що веб-сторінки отримують нульове повідомлення про те, що важливий елемент інтерфейсу змінився, просто сміхотворне. Це справді помилка в специфікації, оскільки вона ніколи не була призначена для повноекранного інтерфейсу медіа-захоплення, а не викликати подію "зміни" технічно є специфікацією.
Однак чи можуть продавці браузерів визнати реальність цього? Це може бути вирішено або за допомогою нової події "зроблено", яка запускається навіть тоді, коли не відбувається жодної зміни, або ви можете просто викликати "зміни" в будь-якому випадку. Так, це було б проти спекуляцій, але для мене тривіально вважати подію зміни на стороні JavaScript, але принципово неможливо винайти мою власну "зроблену" подію. Навіть моє рішення насправді є просто евристикою, якщо немає гарантій щодо стану браузера.
Як відомо, цей API принципово непридатний для мобільних пристроїв, і я думаю, що відносно проста зміна веб-переглядача може зробити це нескінченно простішим для веб-розробників * кроками з мильної коробки *.
Коли ви вибираєте файл і натискаєте кнопку "Відкрити / скасувати", input
елемент повинен втратити фокус ака blur
. Якщо припустити, що початкове value
значення input
порожнє, будь-яке не порожнє значення у вашому blur
оброблювальному пристрої означатиме ОК, а порожнє значення означатиме Скасувати.
ОНОВЛЕННЯ: Значок blur
не спрацьовує, коли input
приховано. Тому не можна використовувати цей трюк для завантажень на основі IFRAME, якщо ви не бажаєте тимчасово відобразити input
.
blur
не спрацьовує при виборі файлу. Не намагався в інших браузерах.
/* Tested on Google Chrome */
$("input[type=file]").bind("change", function() {
var selected_file_name = $(this).val();
if ( selected_file_name.length > 0 ) {
/* Some file selected */
}
else {
/* No file selected or cancel/close
dialog button clicked */
/* If user has select a file before,
when they submit, it will treated as
no file selected */
}
});
else
оцінюється ваша заява?
Більшість цих рішень для мене не працюють.
Проблема в тому, що ти ніколи не знаєш, яка подія спричинить кулак, це click
чи це change
? Ви не можете приймати жодне замовлення, оскільки це, мабуть, залежить від реалізації браузера.
Принаймні, в Opera та Chrome (кінець 2015 року) click
спрацьовує безпосередньо перед «заповненням» введення файлами, тож ви ніколи не дізнаєтесь тривалість, files.length != 0
доки не відкладете, click
щоб її запустили після change
.
Ось код:
var inputfile = $("#yourid");
inputfile.on("change click", function(ev){
if (ev.originalEvent != null){
console.log("OK clicked");
}
document.body.onfocus = function(){
document.body.onfocus = null;
setTimeout(function(){
if (inputfile.val().length === 0) console.log("Cancel clicked");
}, 1000);
};
});
Просто слухайте також подію натискання.
Наслідуючи приклад Шибо, ось приклад jQuery:
var godzilla = $('#godzilla');
var godzillaBtn = $('#godzilla-btn');
godzillaBtn.on('click', function(){
godzilla.trigger('click');
});
godzilla.on('change click', function(){
if (godzilla.val() != '') {
$('#state').html('You have chosen a Mech!');
} else {
$('#state').html('Choose your Mech!');
}
});
Ви можете побачити його в дії тут: http://jsfiddle.net/T3Vwz
Ви можете зловити скасування, якщо ви вибрали той самий файл, що і раніше, і натисніть кнопку Скасувати: у цьому випадку.
Ви можете зробити це так:
<input type="file" id="myinputfile"/>
<script>
document.getElementById('myinputfile').addEventListener('change', myMethod, false);
function myMethod(evt) {
var files = evt.target.files;
f= files[0];
if (f==undefined) {
// the user has clicked on cancel
}
else if (f.name.match(".*\.jpg")|| f.name.match(".*\.png")) {
//.... the user has choosen an image file
var reader = new FileReader();
reader.onload = function(evt) {
try {
myimage.src=evt.target.result;
...
} catch (err) {
...
}
};
}
reader.readAsDataURL(f);
</script>
Найпростіший спосіб - це перевірити наявність файлів у тимчасовій пам'яті. Якщо ви хочете отримати подію зміни кожного разу, коли користувач натискає на вхід файлу, ви можете його запустити.
var yourFileInput = $("#yourFileInput");
yourFileInput.on('mouseup', function() {
$(this).trigger("change");
}).on('change', function() {
if (this.files.length) {
//User chose a picture
} else {
//User clicked cancel
}
});
Рішення Shiboe було б добре, якби він працював на мобільному веб-коді, але це не так. Що я можу придумати - це додати слухача події миші до якогось об'єкта dom під час відкриття вікна введення файлу, наприклад:
$('.upload-progress').mousemove(function() {
checkForFiles(this);
});
checkForFiles = function(me) {
var filefield = $('#myfileinput');
var files = filefield.get(0).files;
if (files == undefined || files[0] == undefined) $(me).remove(); // user cancelled the upload
};
Подія переходу миші блокується зі сторінки, коли відкрито діалогове вікно файлу, а коли закрите, перевіряє, чи є у файлі вхідні файли. У моєму випадку я хочу, щоб індикатор активності блокував речі до завантаження файлу, тому я хочу лише видалити свій індикатор при скасуванні.
Однак це не вирішує для мобільних пристроїв, оскільки миша не рухається. Моє рішення там менш ніж ідеальне, але я вважаю, що його досить добре.
$('.upload-progress').bind('touchstart', function() {
checkForFiles(this);
});
Тепер ми слухаємо дотик на екрані, щоб перевірити ті самі файли. Я майже впевнений, що пальчик користувача буде виставлений на екран досить швидко після скасування та відхилення цього показника активності.
Можна також просто додати індикатор активності у події зміни вводу файлу, але на мобільному пристрої часто відбувається затримка між вибором зображення та зйомкою події зміни, тому його просто набагато краще UX для відображення індикатора активності на початок процесу.
Я знайшов цю приналежність, її найпростішу поки що.
if ($('#selectedFile')[0].files.length > 1)
{
// Clicked on 'open' with file
} else {
// Clicked on 'cancel'
}
Ось, selectedFile
є input type=file
.
Я знаю, що це дуже давнє запитання, але на всякий випадок, якщо він комусь допомагає, я виявив, що використовуючи подію onmousemove для виявлення скасування, що потрібно перевірити дві та більше таких подій за короткий проміжок часу. Це сталося через те, що одиничні події onmousemove генеруються браузером (Chrome 65) щоразу, коли курсор виводиться з діалогового вікна вибору файлу і кожного разу переміщується з головного вікна та назад. Простий лічильник подій руху миші в поєднанні з короткою тривалістю таймауту для скидання лічильника до нуля працювало частування.
У моєму випадку мені довелося сховати кнопку подання, коли користувачі вибирали зображення.
Ось що я придумую:
$(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
- це мій вибір файлів. Коли хтось натискає на нього, я відключаю кнопку подання форми. Справа в тому, що діалогове вікно файлу закрите - неважливо, вони вибирають файл або скасовують - #image-field
отримали фокус назад, тому я слухаю цю подію.
ОНОВЛЕННЯ
Я виявив, що це не працює в сафарі та полтергейсті / фантомі. Враховуйте цю інформацію, якщо ви хочете її реалізувати.
Поєднуючи рішення Shiboe та Alx, я отримав найнадійніший код:
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 робить трюк, але у випадку, якщо користувач здійснив клацання і ніж:
... ми не перейдемо до події миші, а отже, не скасувати зворотний виклик. Крім того, якщо користувач скасує друге діалогове вікно і зробить рух миші, ми отримаємо 2 скасування зворотних викликів. На щастя, спеціальні jQuery focusIn події пускаються до документа в обох випадках, що допомагає нам уникнути подібних ситуацій. Єдине обмеження - якщо один блокує події focusIn.
mousemove
подію document
під час вибору файлів у діалоговому вікні ОС Chrome в Chrome 56.0.2924.87 на Ubuntu 16.10. Немає проблем, коли не рухаєте мишу або використовуєте лише клавіатуру для вибору файлу. Мені довелося замінити mousemove
, keydown
щоб виявити скасування якомога раніше, але не "занадто рано", коли діалогове вікно було ще відкрито.
Я бачу, що моя відповідь була б досить застарілою, але ніколи не менш. Я зіткнувся з тією ж проблемою. Тож ось моє рішення. Найкорисніший фрагмент коду був 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);
});
Виявити це можна лише за обмежених обставин. Зокрема, у хромі, якщо файл було обрано раніше, а потім натискається діалогове вікно файлу та клацання його скасовується, Chrome очищує файл та запускає подію onChange.
https://code.google.com/p/chromium/isissue/detail?id=2508
У цьому випадку ви можете виявити це, обробляючи подію onChange та перевіряючи властивості файлів .
Наступне, здається, працює для мене (на робочому столі, 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.
Поле file
типу, розчаровує, не реагує на багато подій (розмиття було б чудовим). Я бачу дуже багато людей, які пропонують change
орієнтовані рішення, і їм стає недоцільним.
change
дійсно працює, але він має головний недолік (проти того, що ми хочемо, щоб це сталося).
Коли ви щойно завантажуєте сторінку, що містить поле файлу, відкрийте поле та натисніть Скасувати. Ніщо, розчаровує, не змінюється .
Що я вирішив зробити - це завантаження в закритому стані.
section#after-image
в моєму випадку прихована від перегляду. Коли я file field
зміниться, відображається кнопка завантаження. Після успішного завантаження section#after-image
відображається.change
подія викликається цим скасуванням, і там я можу (і зробити) повторно приховати кнопку завантаження, поки не буде обраний належний файл.Мені пощастило, що ця держава із закритим типом вже була дизайном моєї форми. Вам не потрібно використовувати один і той же стиль, просто натискаючи кнопку завантаження спочатку прихованою та після зміни, встановивши приховане поле чи змінну javascript на те, що ви можете контролювати при поданні.
Я спробував змінити значення файлів [0], перш ніж поле було взаємодіяне з. Це не зробило нічого щодо зміни.
Так що так, change
працює, принаймні так добре, як ми збираємося отримати. Файлове поле захищене, з очевидних причин, але на розчарування добровільних розробників.
Це не відповідає моєму призначенню, але ви, можливо, зможете onclick
завантажити завантажувальний запит (не alert()
, тому що це зупиняє обробку сторінки) і приховати її, якщо ініціюється зміна, а файли [0] недійсні. Якщо зміни не спрацьовують, div залишається у своєму стані.
Існує шалений спосіб зробити це (додати зворотні дзвінки або вирішити якусь відстрочену / обіцяючу реалізацію замість 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).
Але, звичайно, це не надійний спосіб виявити скасований діалог. Хоча це може покращити поведінку інтерфейсу для вас.
Ось моє рішення, використовуючи фокус введення файлу (не використовуючи жодних таймерів)
var fileInputSelectionInitiated = false;
function fileInputAnimationStart() {
fileInputSelectionInitiated = true;
if (!$("#image-selector-area-icon").hasClass("fa-spin"))
$("#image-selector-area-icon").addClass("fa-spin");
if (!$("#image-selector-button-icon").hasClass("fa-spin"))
$("#image-selector-button-icon").addClass("fa-spin");
}
function fileInputAnimationStop() {
fileInputSelectionInitiated = false;
if ($("#image-selector-area-icon").hasClass("fa-spin"))
$("#image-selector-area-icon").removeClass("fa-spin");
if ($("#image-selector-button-icon").hasClass("fa-spin"))
$("#image-selector-button-icon").removeClass("fa-spin");
}
$("#image-selector-area-wrapper").click(function (e) {
$("#fileinput").focus();
$("#fileinput").click();
});
$("#preview-image-wrapper").click(function (e) {
$("#fileinput").focus();
$("#fileinput").click();
});
$("#fileinput").click(function (e) {
fileInputAnimationStart();
});
$("#fileinput").focus(function (e) {
fileInputAnimationStop();
});
$("#fileinput").change(function(e) {
// ...
}
Error: { "message": "Uncaught SyntaxError: missing ) after argument list", "filename": "https://stacksnippets.net/js", "lineno": 51, "colno": 1 }
Це в кращому випадку хакі, але ось робочий приклад мого рішення щодо виявлення того, завантажив чи ні користувач файл, і дозволяти їм продовжуватись лише тоді, коли він завантажив файл.
В основному приховати 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 дуже багато цього - зробити веб-сайт та кнопку доступними для всіх. Стилюйте свою кнопку до всього, що вам подобається.
Ну, це точно не відповідає на ваше запитання. Моє припущення полягає в тому, що у вас є сценарій, коли ви додаєте введення файлу і викликаєте вибір файлу, і якщо користувачі звертаються до скасувати, ви просто видаліть введення.
Якщо це так, то: Навіщо додавати порожній файл?
Створіть його на льоту, але додайте його до DOM лише тоді, коли він заповнений.
var fileInput = $("<input type='file' name='files' style='display: none' />");
fileInput.bind("change", function() {
if (fileInput.val() !== null) {
// if has value add it to DOM
$("#files").append(fileInput);
}
}).click();
Тому тут я створюю <input type = "file" /> на льоту, прив'язуюсь до події зміни, а потім негайно викликаю клацання. При зміні буде запущено лише тоді, коли користувач вибере файл і натисне Ок, інакше введення не буде додано до DOM, тому не буде подано.
Приклад роботи тут: https://jsfiddle.net/69g0Lxno/3/
Якщо вам вже потрібна JQuery, це рішення може зробити свою роботу (це саме той самий код, який я насправді потрібен у моєму випадку, хоча використання Обіцяння просто для того, щоб змусити код чекати, поки вибір файлу не буде вирішений):
await new Promise(resolve => {
const input = $("<input type='file'/>");
input.on('change', function() {
resolve($(this).val());
});
$('body').one('focus', '*', e => {
resolve(null);
e.stopPropagation();
});
input.click();
});
У цій темі є кілька запропонованих рішень, і ця складність у виявленні, коли користувач натискає кнопку "Скасувати" у вікні вибору файлів, є проблемою, яка зачіпає багатьох людей.
Справа в тому, що немає 100% надійного способу виявити, чи користувач натиснув кнопку "Скасувати" у вікні вибору файлів. Але є способи надійного виявлення, чи додав користувач файл до вхідного файлу. Отже, це основна стратегія цієї відповіді!
Я вирішив додати цю відповідь, оскільки, мабуть, інші відповіді не працюють у більшості браузерів або гарантуються на мобільних пристроях.
Коротко код заснований на 3 балах:
Для кращого розуміння дивіться код нижче та примітки.
[...]
<button type="button" onclick="addIptFl();">ADD INPUT FILE!</button>
<span id="ipt_fl_parent"></span>
[...]
function dynIptFl(jqElInst, funcsObj) {
if (typeof funcsObj === "undefined" || funcsObj === "") {
funcsObj = {};
}
if (funcsObj.hasOwnProperty("before")) {
if (!funcsObj["before"].hasOwnProperty("args")) {
funcsObj["before"]["args"] = [];
}
funcsObj["before"]["func"].apply(this, funcsObj["before"]["args"]);
}
var jqElInstFl = jqElInst.find("input[type=file]");
// NOTE: Open the file selection box via js. By Questor
jqElInstFl.trigger("click");
// NOTE: This event is triggered if the user selects a file. By Questor
jqElInstFl.on("change", {funcsObj: funcsObj}, function(e) {
// NOTE: With the strategy below we avoid problems with other unwanted events
// that may be associated with the DOM element. By Questor
e.preventDefault();
var funcsObj = e.data.funcsObj;
if (funcsObj.hasOwnProperty("after")) {
if (!funcsObj["after"].hasOwnProperty("args")) {
funcsObj["after"]["args"] = [];
}
funcsObj["after"]["func"].apply(this, funcsObj["after"]["args"]);
}
});
}
function remIptFl() {
// NOTE: Remove the input file. By Questor
$("#ipt_fl_parent").empty();
}
function addIptFl() {
function addBefore(someArgs0, someArgs1) {
// NOTE: All the logic here happens just before the file selection box opens.
// By Questor
// SOME CODE HERE!
}
function addAfter(someArgs0, someArgs1) {
// NOTE: All the logic here happens only if the user adds a file. By Questor
// SOME CODE HERE!
$("#ipt_fl_parent").prepend(jqElInst);
}
// NOTE: The input file is hidden as all manipulation must be done via js.
// By Questor
var jqElInst = $('\
<span>\
<button type="button" onclick="remIptFl();">REMOVE INPUT FILE!</button>\
<input type="file" name="input_fl_nm" style="display: block;">\
</span>\
');
var funcsObj = {
before: {
func: addBefore,
args: [someArgs0, someArgs1]
},
after: {
func: addAfter,
// NOTE: The instance with the input file ("jqElInst") could be passed
// here instead of using the context of the "addIptFl()" function. That
// way "addBefore()" and "addAfter()" will not need to be inside "addIptFl()",
// for example. By Questor
args: [someArgs0, someArgs1]
}
};
dynIptFl(jqElInst, funcsObj);
}
Дякую! = D
Ми досягли такого, як нижче.
<input type="file" formControlName="FileUpload" click)="handleFileInput($event.target.files)" />
/>
this.uploadPanel = false;
handleFileInput(files: FileList) {
this.fileToUpload = files.item(0);
console.log("ggg" + files);
this.uploadPanel = true;
}
@HostListener("window:focus", ["$event"])
onFocus(event: FocusEvent): void {
if (this.uploadPanel == true) {
console.log("cancel clicked")
this.addSlot
.get("FileUpload")
.setValidators([
Validators.required,
FileValidator.validate,
requiredFileType("png")
]);
this.addSlot.get("FileUpload").updateValueAndValidity();
}
}
Просто додайте слухача "змінити" на вхід, тип якого - файл. тобто
<input type="file" id="file_to_upload" name="file_to_upload" />
Я зробив за допомогою jQuery і, очевидно, кожен може використовувати валіну JS (відповідно до вимоги).
$("#file_to_upload").change(function() {
if (this.files.length) {
alert('file choosen');
} else {
alert('file NOT choosen');
}
});
.change()
не надійно викликається, якщо користувач натискає "скасувати" на засобі вибору файлів.
enter code here
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
<h1>Hello</h1>
<div id="cancel01">
<button>Cancel</button>
</div>
<div id="cancel02">
<button>Cancel</button>
</div>
<div id="cancel03">
<button>Cancel</button>
</div>
<form>
<input type="file" name="name" placeholder="Name" />
</form>
<script>
const nameInput = document.querySelector('input[type="file"]');
/******
*The below code if for How to detect when cancel is clicked on file input
******/
nameInput.addEventListener('keydown', e => {
/******
*If the cancel button is clicked,then you should change the input file value to empty
******/
if (e.key == 'Backspace' || e.code == 'Backspace' || e.keyCode == 8) {
console.log(e);
/******
*The below code will delete the file path
******/
nameInput.value = '';
}
});
</script>
</body>
</html>
Примітка: цей код не виявляє скасування, він пропонує спосіб обійти необхідність його виявлення у звичайному випадку, коли люди намагаються його виявити.
Я потрапив сюди, шукаючи рішення для завантаження файлів за допомогою прихованого вводу, я вважаю, що це найпоширеніша причина шукати спосіб виявлення скасування введення файлу (відкрити діалогове вікно файлу -> якщо файл був обраний, тоді запустіть деякий код, інакше нічого не робити), ось моє рішення:
var fileSelectorResolve;
var fileSelector = document.createElement('input');
fileSelector.setAttribute('type', 'file');
fileSelector.addEventListener('input', function(){
fileSelectorResolve(this.files[0]);
fileSelectorResolve = null;
fileSelector.value = '';
});
function selectFile(){
if(fileSelectorResolve){
fileSelectorResolve();
fileSelectorResolve = null;
}
return new Promise(function(resolve){
fileSelectorResolve = resolve;
fileSelector.dispatchEvent(new MouseEvent('click'));
});
}
Зауважте, що якщо не було обрано жодного файлу, то перший рядок повертається лише один раз, коли selectFile()
він знову викликається (або якщо ви дзвонили fileSelectorResolve()
з іншого місця).
async function logFileName(){
const file = await selectFile();
if(!file) return;
console.log(file.name);
}
Ще один приклад:
async function uploadFile(){
const file = await selectFile();
if(!file) return;
// ... make an ajax call here to upload the file ...
}
Ви можете зробити слухача зміни jquery у полі введення та виявити, що користувач скасує або закриє вікно завантаження за значенням поля.
ось приклад:
//when upload button change
$('#upload_btn').change(function(){
//get uploaded file
var file = this.files[0];
//if user choosed a file
if(file){
//upload file or perform your desired functiuonality
}else{
//user click cancel or close the upload window
}
});
e.target.files