Мультизагрузка картинок
Доброго дня всем
Есть форма и инпут типа 'file' с атрибутом 'multiple'. Также имется предпросмотр выбранных картинок. Когда юзер выбирает сразу несколько изображений, то они все попадают в массив $_FILES и все работает нормально. Но если юзер выбирает одну картинку, закрывает окно выбора, потом следующую и т.д., то в массив $_FILES попадает последняя. При этом в окне предпросмотра все они показываются нормально. Такой вопрос - как их объединить, чтобы все работало так, как будто выбираются сразу несколько файлов? Код предпросмотра window.onload = function(){ //Check File API support if(window.File && window.FileList && window.FileReader){ var filesInput = document.getElementById("files"); filesInput.addEventListener("change", function(event){ var files = event.target.files; //FileList object var output = document.getElementById("result"); for(var i = 0; i< files.length; i++){ var file = files[i]; //Only pics if(!file.type.match('image')) continue; var picReader = new FileReader(); picReader.addEventListener("load",function(event){ var picFile = event.target; var div = document.createElement("div"); div.className = 'img_preview'; div.innerHTML = "<img class='thumbnail' src='" + picFile.result + "'" + "title='" + picFile.name + "'/>"; output.insertBefore(div,null); }); //Read the image picReader.readAsDataURL(file); } }); } else { console.log("Your browser does not support File API"); } } Спасибо |
Нужно удалять все превью, когда пользователь просто закрывает окно выбора файла, т.к. все выбранные до этого файлы "сбрасываются".
После строки 11: if(!files.length) output.innerHTML=''; |
Цитата:
|
Nexus,
похоже вопрос в том как отправить ВСЕ картинки из output на сервер? |
Цитата:
|
<input type="file" multiple id="files" accept="image/*"/> <div id="result"></div> <style>.thumbnail{max-width:100px;}</style> <script> (function(){ if(!window.File || !window.FileList || !window.FileReader) return console.log("Your browser does not support File API"); document.getElementById("files").addEventListener("change", function(event) { var files = event.target.files, output = document.getElementById("result"); output.innerHTML = ''; for(var i = 0; i < files.length; i++) { var file = files[i]; if(!file.type.match('image')) continue; var picReader = new FileReader(); picReader.addEventListener("load", function(event) { var picFile = event.target; var div = document.createElement("div"); div.className = 'img_preview'; div.innerHTML = "<img class='thumbnail' src='" + picFile.result + "'" + "title='" + picFile.name + "'/>"; output.insertBefore(div, null); }); picReader.readAsDataURL(file); } }); })(); </script> Сейчас скрипт работает правильно, он всегда отрисовывает только действительно выбранные изображения, которые и будут отправлены на сервер. Чтобы реализовать возможность последовательного/поочередного выбора изображений для загрузки нужно либо сохранять выбранные пользователем изображения в переменной и отправлять их на сервер скриптом, либо каждый раз клонировать поле выбора файла (в этом случае обработчик лучше делегировать ближайшему родителю). |
рони, вероятно вы правы.
|
Цитата:
|
LingVist,
копайте в сторону FormData |
Цитата:
|
Теоретически должно работать.
<div id="files"> <input type="file" multiple accept="image/*"/> </div> <div id="result"></div> <style> .img_preview{display:inline-block;} .thumbnail{max-width:100px;} #files input{display:none;} #files input:last-child{display:block;} </style> <script> (function(){ if(!window.File || !window.FileList || !window.FileReader) return console.log("Your browser does not support File API"); document.getElementById("files").addEventListener("change", function(event) { var clone = event.target.cloneNode(), files = event.target.files, output = document.getElementById("result"); clone.value=null; this.appendChild(clone); this.focus(); for(var i = 0; i < files.length; i++) { var file = files[i]; if(!file.type.match('image')) continue; var picReader = new FileReader(); picReader.addEventListener("load", function(event) { var picFile = event.target; var div = document.createElement("div"); div.className = 'img_preview'; div.innerHTML = "<img class='thumbnail' src='" + picFile.result + "'" + "title='" + picFile.name + "'/>"; output.insertBefore(div, null); }); picReader.readAsDataURL(file); } }); })(); </script> |
Цитата:
|
Цитата:
|
Цитата:
|
Цитата:
|
Цитата:
https://developer.mozilla.org/ru/doc...% D0%B8%D1%81 |
Цитата:
picReader.readAsDataURL(file); Взять из src base64 и отправить можно. Но это будет объем в три раза меньше разрешенного сервером, и это будут данные в $_POST. |
Цитата:
Сервер, по идее, должен получить файл не в глобальном объекте _post, но _files. |
Какой file, если речь об output, который html? )
|
laimas, виноват, упустил упоминание "output" в посте рони.
|
Nexus,
можно и файлом передать, но для этого надо обратное - base64 -> Blob. А вот стоит ли это делать вместо добавления нового поля, это уже вопрос философский. ) |
Возможно я вас увёл в сторону, FormData.append все files (не знаю формат) дополнять при каждом change, а не из output.
|
рони,
можно, но в этом случае нужно решать и вопросы связанные с отказом загружать что-то из ранее выбранного. |
laimas, по-моему это не такой уж и философский вопрос.
Декодирование base64 займет некоторое время, так и нагрузит устройство пользователя. А плюсы этого деяния весьма сомнительны, т.к. нет никаких трудностей в том, чтобы на сервере обработать файл как post, либо, как вы и написали, просто добавить новое поле, которое избавит от дополнительных манипуляций (это, конечно, если синхронный запрос устраивает). |
Цитата:
|
|
рони, FormData в памяти устройства же будет храниться?
Т.е. данные будут как в base64 в src preview, так и в объекте FormData единовременно? |
Цитата:
|
рони,
ну так надо связывать каждый отображаемый эскиз в output с данными в FormData. Именовать каждый элемент в наборе уникальным именем, это значит усложнить обработку на сервере. Работать с индексным набором, придется следить что имеется уже (имя поля ввода обязательно должно отражать массив - name[], в противном случае РНР отдаст последний в наборе файл). |
laimas, проверить размер файла перед сохранением все же можно.
|
Цитата:
|
Цитата:
|
laimas, в php есть директива "post_max_size".
Правда как поступит сервер, если клиент превысит этот лимит я не знаю. |
Nexus, предложенный Вами вариант также не работает, передается пустой массив.
В обработчике РНР для загрузки файлов в папку я использую цикл $array = array(); foreach ($request->file() as $file) { foreach ($file as $img) { $img->move(public_path().'/'.env('THEME').'/images/estate/'.$upload_dir, date('dmY_Hi').'_'.$img->getClientOriginalName()); $img = date('dmY_Hi').'_'.$img->getClientOriginalName(); array_push($array, $img); } } В массив $array добавляются имена изображений, потом закидываю их в БД одной строкой. Может подобным образом можно создать массив и с самими картинками? Только как это сделать технически, я не знаю |
LingVist, вы имя инпуту указали?
upd. Цитата:
|
Цитата:
|
laimas,
Цитата:
Я верно понял? |
Цитата:
|
Цитата:
|
FileReader здесь не нужен. Правильнее использовать URL.createObjectURL, и не забыть про URL.revokeObjectURL.
Итого, никакого base64 тут не надо. Т.е. не будет копии файла в оперативной памяти. Все выбираемые файлы складывать в массив, потом из этого массива добавить в FormData перед отправкой. |
Часовой пояс GMT +3, время: 07:55. |