Тарифы Услуги Сим-карты

Красивая ajax загрузка нескольких изображений на сервер. Загрузка файлов на сервер с помощью ajax

Последнее обновление: 1.11.2015

В статье были рассмотрены общие моменты оптравки файлов на сервер в обычном запросе POST. Но если мы используем Ajax-запросы, то загрузка файлов будет иметь свои особенности.

Сначала определим метод в контроллере MVC:

Public JsonResult Upload() { foreach (string file in Request.Files) { var upload = Request.Files; if (upload != null) { // получаем имя файла string fileName = System.IO.Path.GetFileName(upload.FileName); // сохраняем файл в папку Files в проекте upload.SaveAs(Server.MapPath("~/Files/" + fileName)); } } return Json("файл загружен"); }

Здесь предполагается, что у нас в проекте определена папка Files для хранения загруженных файлов. Для получения файлов используется коллекция Request.Files

После сохранения файла пользователю отдается результат в виде строки.

Код представления тогда будет выглядеть следующим образом:

@{ ViewBag.Title = "Home Page"; }
Загрузить @section scripts{ $("#submit").on("click", function (e) { e.preventDefault(); var files = document.getElementById("uploadFile").files; if (files.length > 0) { if (window.FormData !== undefined) { var data = new FormData(); for (var x = 0; x < files.length; x++) { data.append("file" + x, files[x]); } $.ajax({ type: "POST", url: "@Url.Action("Upload", "Home")", contentType: false, processData: false, data: data, success: function (result) { alert(result); }, error: function (xhr, status, p3) { alert(xhr.responseText); } }); } else { alert("Браузер не поддерживает загрузку файлов HTML5!"); } } }); }

Нам не нужна стандартная форма, все делается через ajax. Сначала получаем все выбранные файлы:

Var files = document.getElementById("uploadFile").files

Затем формируем объект FormData , в который добавляем все выбранные файлы:

Var data = new FormData(); for (var x = 0; x < files.length; x++) { data.append("file" + x, files[x]); }

И отсылаем их на сервер.

Асинхронная загрузка файлов в WebAPI

В Web API контроллер будет выглядеть следующим образом:

Public class ValuesController: ApiController { public async Task Post() { if (!Request.Content.IsMimeMultipartContent()) { return BadRequest(); } var provider = new MultipartMemoryStreamProvider(); // путь к папке на сервере string root = System.Web.HttpContext.Current.Server.MapPath("~/Files/"); await Request.Content.ReadAsMultipartAsync(provider); foreach (var file in provider.Contents) { var filename = file.Headers.ContentDisposition.FileName.Trim("\""); byte fileArray = await file.ReadAsByteArrayAsync(); using (System.IO.FileStream fs = new System.IO.FileStream(root + filename, System.IO.FileMode.Create)) { await fs.WriteAsync(fileArray, 0, fileArray.Length); } } return Ok("файлы загружены"); } }

Здесь используется асинхронная обработка запроса. Вначале метод IsMultipartContent() проверяет, содержит ли запрос корректные данные. Если нет, то возвращаем статусный код 401.

Для асинхронного чтения с потока создается провайдер:

Var provider = new MultipartMemoryStreamProvider(); Request.Content.ReadAsMultipartAsync(provider);

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

Byte fileArray = await file.ReadAsByteArrayAsync();

Затем с помощью объекта FileStream считанный массив сохраняется на диске в папке проекта.

Представление будет тем же, что и для MVC, за исключением url запроса:

$.ajax({ type: "POST", url: "api/values/post", contentType: false, processData: false, data: data, success: function (result) { alert(result); }, error: function (xhr, status, p3) { alert(status); } });

Добрый день!

Долгое время на просторах интернета я искал информацию о реализации AJAX загрузки файлов для CodeIgniter. Разные разработчики предлагали разные технологии и примеры реализации. Я перепробовал их все, но ни одна из них не была достаточно проста и функциональна одновременно. Лишь недавно я открыл для себя jQuery File Uploader . «Он ничем не отличается от остальных» - скажите вы, но это не так. Его главное отличие - это простота и хорошая документация с примерами. В документации разобраны все callback"и, описаны все options. Внедрение в любую систему не занимает много времени.

Сегодня я покажу как можно очень просто организовать multipart загрузку файлов на сервер + drug&drop в CodeIgniter.

jQuery File Uploader + CodeIgniter Из коробки CodeIgniter предлагает нам использовать библиотеку $this->load->library("upload"); , которая позволяет контролировать передаваемые файлы, ограничивая загрузку по типу, размеру, ширине и высоте изображения. Использовать ее легко и удобно, но следует отметить небольшое ограничение налагаемое на INPUT данной библиотекой. Поле INPUT должно обязательно иметь параметр name=«userfile» . Соглашаемся с этим фактом и переходим в Controller к функции которая будет вызывать библиотеку Upload и, собственно, сохранять наши файлы на диск.

Пример реализации PHP функции:
public function upload(){ $config["upload_path"] = "/application/uploads/"; $config["allowed_types"] = "jpg|jpeg|png|gif|flv|mp4|wmv|doc|docx|xsl|xslx|ppt|pptx|zip|rar|tar"; $config["max_size"] = 2048; $config["max_width"] = 800; $config["max_height"] = 600; $config["encrypt_name"] = TRUE; $this->load->library("upload", $config); if ($this->upload->do_upload() == false) { $error = array("error" => $this->upload->display_errors()); echo json_encode($error); }else{ $data = $this->upload->data(); echo json_encode($data); } }

Внимание! Для того, что бы у Вас работали все allowed_types необходимо дописать недостающие MIME-Types в конфигурационный файл /application/config/mimes.php

У нас готова функция для сохранения файла на сервер. Переходим к клиентской части. Нам понадобится скачать с Github jQuery File Upload . Плагин предоставляет большие возможности, но все их использовать мы не будет, воспользуемся лишь загрузкой нескольких файлов, drug&drop и progressall.

Подключаем на страницу загрузки необходимые JS:
- jquery.fileupload.js - jquery.fileupload-video.js - jquery.fileupload-process.js - jquery.iframe-transport.js - upload.js //В комплекте не идет - напишем сами

И CSS файл:
- css/jquery.fileupload.css

Добавляем наш INPUT на страницу:
Добавить файл

Осталось совсем не много - написать upload.js, который будет прослушивать событие изменения поля INPUT и вызывать загрузку выбранного файла. «А где же обещанный Drug&Drop?» - спросите Вы. Drug&Drop уже работает благодаря jQuery File Upload. Вместо вызова стандартного диалога выбора файла вы можете перетащить сразу несколько файлов на страницу и они в порядке очереди загрузятся на сервер.

И на последок Upload.js
$(document).ready(function(){ $("#fileupload").fileupload({ dataType: "json", progressall: function (e, data) { var progress = parseInt(data.loaded / data.total * 100, 10); $(".progress .bar").css("width", progress + "%"); }, done: function (e, data) { if(data.result.error != undefined){ $("#error").html(data.result.error); // выводим на страницу сообщение об ошибке если оно есть $("#error").fadeIn("slow"); }else{ $("#error").hide(); //на случай если сообщение об ошибке уже отображалось $("#files").append(""); $("#success").fadeIn("slow"); } } } }); });

Data - это наш ответ от сервера, но он не является массивом с информацией о загруженном файле. Вся информация в формате JSON хранится в Data.Result. Кстати говоря console.log(data) поможет найти много интересных вещей, таких как: количество отправленных файлов, ошибки и многое другое.

Вот собственно и все, надеюсь на полезность материала.

В сети существует множество библиотек реализующих загрузку файлов на сервер. Так что у разработчика есть широкий выбор каким инструментом можно воспользоваться. Но порой они довольно сложные для новичком. Изначально для статьи было решено написать простую библиотеку, которую будет легко понять. Но по счастью в сети была найдена довольно простая реализация загрузки фалов, которой было и решено воспользоваться. Называется она dmuploader и является плагином для jQuery.

С помощью dmuploader мы создадим загрузчик, похожий по дизайну на тот, что реализован в wordpress. С Drag And Drop’ом и кликами! Преступим!

Структура проекта:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 #dropzone { border : 4px dashed #bbb ; border-radius : 5px ; color : #444 ; padding : 25px ; text-align : center ; } #dropzone .title { font-size : 20px ; } #dropzone input { -moz-border-bottom-colors: none ; -moz-border-left-colors: none ; -moz-border-right-colors: none ; -moz-border-top-colors: none ; border-color : transparent ; border-image: none ; cursor : pointer ; direction : ltr ; margin : 0 ; opacity: 0 ; position : absolute ; right : 0 ; top : 0 ; transform: translate(-300px , 0px ) scale(4 ) ; } #dropzone .browser span { background : #f7f7f7 ; border : 1px solid #ccc ; color : #555 ; cursor : pointer ; font-size : 16px ; height : 46px ; line-height : 44px ; padding : 0 36px ; } #dropzone .browser span:hover { border : 1px solid #999 ; }

Javascript:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 // index.php $(document) .ready (function () { $("#dropzone" ) .dmUploader ({ url: "upload.php" , dataType: "json" , maxFileSize: 256 * 1014 , allowedTypes: "image/*" , onBeforeUpload: function (id) { $) .show () ; } , onUploadSuccess: function (id, response) { $("div#output" ) .html ("" ) ; } , onUploadError: function (id, message) { $.jGrowl ("Файл: " + id + " не загрузился: " + message, { theme: "error" } ) ; } , onFileTypeError: function (file) { $.jGrowl (, { theme: "error" } ) ; } , onFileSizeError: function (file) { $.jGrowl ("Файл слишком большой!!" , { theme: "error" } ) ; } , onFallbackMode: function (message) { $.jGrowl ("Ваш браузер не поддерживается 8(" , { theme: "error" } ) ; } } ) ; } ) ;

Все! Клиенсткая часть готова. Немного подробнее:

  • DmUploader за нас подпишется на события drag для дом элемента #dropzone, а также на событие change для элемента input file.
  • При наступлении одного из событий, будет прочитан локальный файл с помощью file api.
  • У файла будет проверен размер и тип. В нашем случае, только картинки.
  • Удовлетворяющий всем проверкам файл будет загружен на сервер.
  • В процессе работы будут вызываться соответствующие коллбэки (callbacks). Например, onUploadSuccess вызовется после успешной загрузки файла. Вторым аргументом в функцию поступит ответ от сервера в формате json. Коллбэков у библиотеки больше, чем представлено в примере. С помощью них можно реализовать более сложные задачи.
  • Сервер

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 // upload.php require_once __DIR__ . "/protected/bootstrap.php" ; if (! IS_POST() || ! $_FILES ) { stopAndResponseMessage("error" , "Только POST, FILES" } $files = convertFileInformation($_FILES ) ; if (! isset ($files [ "file" ] ) ) { stopAndResponseMessage("error" , "Файл не загружался" ) ; } $file = $files [ "file" ] ; if ($file [ "error" ] !== UPLOAD_ERR_OK) { stopAndResponseMessage( "error" , uploadCodeToMessage($file [ "error" ] ) ) ; } $mimeType = guessMimeType($file [ "tmp_name" ] ) ; if (! $mimeType ) { stopAndResponseMessage("error" , "Тип файла не распознается!" ) ; } $validMimeType = [ "image/png" , "image/jpeg" ] ; if (! in_array ($mimeType , $validMimeType ) ) { stopAndResponseMessage( "error" , "Загружать можно только png и jpeg!" ) ; } $size = filesize ($file [ "tmp_name" ] ) ; if ($size > 256 * 1024 ) { stopAndResponseMessage("error" , "Файл слишком большой!!" ) ; } $uploadDir = __DIR__ . "/files" ; if (! is_writable ($uploadDir ) ) { stopAndResponseMessage( "error" , "Папка для файлов не доступна для записи." ) ; } $filename = time () . "-" . mt_rand (0000 , 9999 ) . "." . guessFileExtension($mimeType ) ; if (! move_uploaded_file ( $file [ "tmp_name" ] , $uploadDir . "/" . $filename ) ) { stopAndResponseMessage("error" , "Файл не был перемецен!" ) ; } sendResponse("upload" , [ "url" => "files/" . $filename ] ) ;

    Стоит заострить особое внимание на функции guessMimeType. Она с помощью расширения FileInfo определяет MIME тип файла. Как видно из кода, тип и размер файла, присланные от браузера не определяются при проверке. Их может подделать злоумышленник.

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 //protected/inc/func.php function guessMimeType($path , $magicFile = null ) { if (! is_file ($path ) ) { return null ; } if (! is_readable ($path ) ) { return null ; } if (! $finfo = new \finfo(FILEINFO_MIME_TYPE, $magicFile ) ) { return ; } return $finfo -> file ($path ) ; }

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

    В наше время веб-сайты становятся все более интерактивными. Это касается не только специализированных сервисов, но и обычных интернет магазинов, блогов и небольших сайтов. Основной особенностью является асинхронный JavaScript и XML сокращенно AJAX . Эта технология позволяет браузеру в фоновом режиме общаться с веб-сервером и при обновлении данных, веб-страница не перезагружается полностью. Другими словами, мы можем делать запросы и получать ответы от сервера не перезагружая страницу в браузере.

    Поскольку наиболее популярным языком для разработки веб-приложений является PHP , то сегодня мы будем использовать связку AJAX и PHP . Пример будет хорош для понимания основных принципов работы с AJAX и PHP .

    На самом деле особых сложностей быть не должно, алгоритм действий:

    • Выбрать картинку
    • Нажать кнопку “Отправить”
    • Перехватить вызов формы с помощью JavaScript (jQuery)
    • Передать содержимое в специальный php скрипт-обработчик
    • Вернуть результат выполнения
    • Обработать результат при помощи JavaScript (jQuery)
    • Вывести пользователю информацию о загрузке
    Кратко о jQuery и AJAX

    Немного отклонюсь от темы и объясню что такое jQuery . jQuery — это специальная JavaScript библиотека, которая помогает упростить разработку веб приложений в несколько раз, также данная библиотека предоставляет API для работы с AJAX . Простыми словами, мы напишем меньше кода, чем если бы это делали на чистом JS.

    Ajax позволяет не перезагружая веб-страницу, обмениваться данными с веб-сервером и обновлять ее содержимое.

    Я склоняюсь к тому, что если есть инструмент, который позволяет вам ускорить разработку без последствий, то почему бы его не использовать? Но чистый JS тоже не помешало бы знать(хоть и лично мой уровень владения JS равен уровню копипаста примеров со stackoverflow 🙂).

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

    Нам понадобится 3 простых файла, это:

    • Страница с формой
    • php обработчик
    • файл js
    index.html Ajax Upload Image upload Image file:

    Обычная html страница с формой. Обратите внимание на enctype="multipart/form-data" , это нужно для передачи файлов, параметр указывает на способ кодирования данных. Если передаете файлы, значение всегда должно быть multipart/form-data .

    handler.php // Проверяем установлен ли массив файлов и массив с переданными данными if(isset($_FILES) && isset($_FILES["image"])) { //Переданный массив сохраняем в переменной $image = $_FILES["image"]; // Проверяем размер файла и если он превышает заданный размер // завершаем выполнение скрипта и выводим ошибку if ($image["size"] > 200000) { die("error"); } // Достаем формат изображения $imageFormat = explode(".", $image["name"]); $imageFormat = $imageFormat; // Генерируем новое имя для изображения. Можно сохранить и со старым // но это не рекомендуется делать $imageFullName = "./images/" . hash("crc32",time()) . "." . $imageFormat; // Сохраняем тип изображения в переменную $imageType = $image["type"]; // Сверяем доступные форматы изображений, если изображение соответствует, // копируем изображение в папку images if ($imageType == "image/jpeg" || $imageType == "image/png") { if (move_uploaded_file($image["tmp_name"],$imageFullName)) { echo "success"; } else { echo "error"; } } }

    Это очень упрощенный обработчик. Имя картинки я сгенерировал использовав функцию hash . Хорошей практикой считается изменять имена файлов при загрузке их на сервер.

    ajaxupload.js $(document).ready(function () { function readImage (input) { if (input.files && input.files) { var reader = new FileReader(); reader.onload = function (e) { $("#preview").attr("src", e.target.result); } reader.readAsDataURL(input.files); } } function printMessage(destination, msg) { $(destination).removeClass(); if (msg == "success") { $(destination).addClass("alert alert-success").text("Файл успешно загружен."); } if (msg == "error") { $(destination).addClass("alert alert-danger").text("Произошла ошибка при загрузке файла."); } } $("#image").change(function(){ readImage(this); }); $("#upload-image").on("submit",(function(e) { e.preventDefault(); var formData = new FormData(this); $.ajax({ type:"POST", // Тип запроса url: "handler.php", // Скрипт обработчика data: formData, // Данные которые мы передаем cache:false, // В запросах POST отключено по умолчанию, но перестрахуемся contentType: false, // Тип кодирования данных мы задали в форме, это отключим processData: false, // Отключаем, так как передаем файл success:function(data){ printMessage("#result", data); }, error:function(data){ console.log(data); } }); })); });

    В этом скрипте происходит самое интересное. При помощи функции readImage() мы будем считывать файл с поля формы и передавать его в блок для предварительного просмотра. Создается объект FileReader . Он позволяет веб-приложению считывать содержимое файла на компьютере пользователя. Событие.onload сработает когда содержимое будет считано, при помощи этого события мы выведем изображение в блок предварительного просмотра.
    И напоследок, метод.readAsDataURL() запускает процесс чтения файла, по завершению чтения будет выполнено событие.onload и картинка появится у вас на экране.

    Функция printMessage создана для вывода информации об успешной или провалившейся попытке загрузки файла. Подробно не рассматриваем, ничего особенного не представляет.

    Перехват формы и её обработка. При клике на кнопку «Отправить» событие будет перехвачено скриптом и при помощи функции.preventDefault() форма не отправит данные в index.html . .preventDefault() служит для отмены вызова каких-либо событий.

    Объект FormData нужен нам для создания POST запроса к нашему скрипту, это намного проще чем вписывать каждый элемент формы в строку. Создали объект, заполнили данными, отдали в наш ajax .

    Ну и собственно сам запрос AJAX . Поскольку мы используем библиотеку jQuery , составить и выполнить такой запрос не вызовет у вас никаких проблем.

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

    Хорошего дня и успехов 🙂

    241

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

    В качестве тестового проекта создайте пустое приложение ASP.NET MVC в Visual Studio. Мы будем использовать C# на бэкенде (как я уже говорил, основное внимание мы уделим написанию JavaScript, так что для серверной части вы можете использовать любой другой язык). Добавьте библиотеку jQuery с помощью диспетчера пакетов NuGet (View --> Other Windows --> Package manager Console):

    Install-Package jQuery

    Добавьте в папку Controllers класс контроллера HomeController.cs со следующим содержимым (напомню, контроллер Home используется по умолчанию в настройках маршрутизации проекта – файл /App_Start/RouteConfig.cs):

    Using System.Web.Mvc; namespace UploadFiles.Controllers { public class HomeController: Controller { public ActionResult Index() { return View(); } } }

    Щелкните правой кнопкой мыши по методу Index и выберите в контекстном меню команду Add View. Visual Studio создаст файл представления /Views/Home/index.cshtml, а также компоновку по умолчанию /Views/Shared/_Layout.cshtml. Давайте подключим библиотеку jQuery в файле компоновки:

    @RenderBody()

    Здесь мы также добавили сброс стилей CSS для браузера и подключили таблицу стилей /Content/Site.css. Добавьте также файл script.js в папку scripts. Давайте теперь добавим форму для загрузки файлов в проект. Для этого откройте представление Index.cshtml и используйте следующую разметку:

    @{ ViewBag.Title = "Index"; }

    Перетащите ваши файлы в эту область!

    0 %

    В элементе section находится форма со вставкой загружаемых файлов. Файлы можно поместить в этот контейнер путем перетаскивания (drag-and-drop) , либо через диалоговое окно после щелчка по элементу section. Элемент progress будет содержать индикатор загрузки файлов, в элементе error будут отображаться ошибки, а контейнер images нужен для отображения сохраненных на сервере картинок.

    Теперь нам нужно добавить CSS-стили для страницы. Для этого отредактируйте файл /Content/Site.css следующим образом:

    Body { font-family:Arial,Helvetica,sans-serif; } section { position: relative; width: 380px; height: 160px; margin: 40px auto; color: #40444f; border: .2rem dashed #616778; border-radius: 1.5rem; cursor: pointer; -webkit-transition: color 0.2s ease-out, border-color 0.2s ease-out; -moz-transition: color 0.2s ease-out, border-color 0.2s ease-out; transition: color 0.2s ease-out, border-color 0.2s ease-out; overflow: hidden; padding-top: 90px; box-sizing: border-box; } section:hover, section.dd { border-color: #4d90ff; color: #4d90ff; background-color: #e7f0fe; } figure { position: absolute; width: 100%; height: 160px; left: 0; top: 0; display: block; } figure:after { position: absolute; display: block; content: ""; height: 80px; width: 80px; top: 5px; left: 50%; margin-left: -40px; background-repeat: no-repeat; background-size: 80px 80px; background-image: url(https://сайт/my/it/blog/net/images/upload_icon.png); -webkit-transition: opacity 0.2s ease-out, border-color 0.2s ease-out; -moz-transition: opacity 0.2s ease-out, border-color 0.2s ease-out; transition: opacity 0.2s ease-out, border-color 0.2s ease-out; } section:hover figure:after, section.dd figure:after { opacity: .65; } p { text-align: center; font-weight: bold; font-size: 16px; line-height: 24px; } p small { font-weight: normal; font-size: 12px; opacity: .7; } { position: absolute; top: -16rem; opacity: 0; } .error { width: 380px; margin: 0 auto 20px; line-height: 20px; font-size: 14px; color: red; font-style: italic; display: none; text-align: center; } /* Прогресс-бар */ .progress { height: 20px; width: 380px; margin: 0 auto 20px; overflow: hidden; background-color: #999; border-radius: 4px; -webkit-box-shadow: inset 0 1px 2px rgba(0,0,0,.1); box-shadow: inset 0 1px 2px rgba(0,0,0,.1); position: relative; display: none; } .progress-bar { height: 100%; font-size: 12px; float: left; width: 0; background-color: #428bca; -webkit-box-shadow: inset 0 -1px 0 rgba(0,0,0,.15); box-shadow: inset 0 -1px 0 rgba(0,0,0,.15); -webkit-transition: width .6s ease; transition: width .6s ease; } .progress-value { position: absolute; left: 0; top: 0; line-height: 20px; height: 100%; width: 100%; color: #fff; text-align: center; } /* Контейнер с загруженными картинками */ .images { width: 380px; overflow: hidden; margin: 0 auto; } .images a { width: 116px; height: 116px; margin: 0 10px 10px 0; float: left; display: block; box-sizing: border-box; padding: 4px; border: 1px solid #d2d2d2; border-radius: 6px; position: relative; } .images a:hover { border-color: #428bcb; } .images span { width: 100%; height: 100%; position: absolute; top: 0; left: 0; display: block; background-repeat: no-repeat; background-size: contain; background-position: center; }

    На данный момент форма выглядит следующим образом:

    Теперь нам нужно добавить скрипт, который должен обеспечивать следующий функционал:

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

      При перетаскивании файлов из проводника в окно браузера, элемент section должен подсвечиваться как при наведении курсора мыши (для этого мы добавили CSS-класс «dd&raqio;). При отпускании файлов (как и при выборе файла из диалогового окна) должна происходить загрузка картинок на сервер.

      При загрузке файлов необходимо добавить индикатор и отобразить процент выполнения загрузки.

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

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

    Следующий скрипт (файл script.js) решает все вышеуказанные вопросы:

    $(function () { // Программное открытие окна выбора файла по щелчку $("figure").on("click", function () { $(":file").trigger("click"); }) // При перетаскивании файлов в форму, подсветить $("section").on("dragover", function (e) { $(this).addClass("dd"); e.preventDefault(); e.stopPropagation(); }); // Предотвратить действие по умолчанию для события dragenter $("section").on("dragenter", function (e) { e.preventDefault(); e.stopPropagation(); }); $("section").on("dragleave", function (e) { $(this).removeClass("dd"); }); $("section").on("drop", function (e) { if (e.originalEvent.dataTransfer) { if (e.originalEvent.dataTransfer.files.length) { e.preventDefault(); e.stopPropagation(); // Вызвать функцию загрузки. Перетаскиваемые файлы содержатся // в свойстве e.originalEvent.dataTransfer.files upload(e.originalEvent.dataTransfer.files); } } }); // Загрузка файлов классическим образом - через модальное окно $(":file").on("change", function () { upload($(this).prop("files")); }); }); // Функция загрузки файлов function upload(files) { // Создаем объект FormData var formData = new FormData(); // Пройти в цикле по всем файлам for (var i = 0; i < files.length; i++) { // С помощью метода append() добавляем файлы в объект FormData formData.append("file_" + i, files[i]); } // Ajax-запрос на сервер $.ajax({ type: "POST", url: "/Home/Upload", // URL на метод действия Upload контроллера HomeController data: formData, processData: false, contentType: false, beforeSend: function () { $("section").removeClass("dd"); // Перед загрузкой файла удалить старые ошибки и показать индикатор $(".error").text("").hide(); $(".progress").show(); // Установить прогресс-бар на 0 $(".progress-bar").css("width", "0"); $(".progress-value").text("0 %"); }, success: function (data) { if (data.Error) { $(".error").text(data.Error).show(); $(".progress").hide(); } else { $(".progress-bar").css("width", "100%"); $(".progress-value").text("100 %"); // Отобразить загруженные картинки if (data.Files) { // Обертка для картинки со ссылкой var img = ""; for (var i = 0; i < data.Files.length; i++) { // Сгенерировать вставляемый элемент с картинкой // (символ 0 заменяем ссылкой с помощью регулярного выражения) var element = $(img.replace(/0/g, data.Files[i])); // Добавить в контейнер $(".images").append(element); } } } }, xhrFields: { // Отслеживаем процесс загрузки файлов onprogress: function (e) { if (e.lengthComputable) { // Отображение процентов и длины прогресс бара var perc = e.loaded / 100 * e.total; $(".progress-bar").css("width", perc + "%"); $(".progress-value").text(perc + " %"); } } }, }); }

    Для сохранения списка файлов и передачи его на сервер через Ajax используется объект FormData .

    Обратите внимание, что за отслеживание процесса загрузки отвечает свойство xhrFields объекта, передаваемого методу $.ajax. В этом свойстве хранится объект с функцией обработки события onprogress . Этому событию передается объект со свойствами loaded – объем уже загруженных данных, и total – общий размер данных. Благодаря этим двум параметрам мы можем отображать процесс выполнения загрузки на индикаторе.

    В методе $.ajax() мы ссылаемся на метод действия Upload контроллера HomeController, который еще не был добавлен. Давайте исправим это и отредактируем файл HomeController.cs:

    Using System; using System.Web; using System.Linq; using System.Web.Mvc; using System.Collections.Generic; using System.IO; namespace UploadFiles.Controllers { public class HomeController: Controller { public ActionResult Index() { return View(); } public JsonResult Upload() { string __filepath = Server.MapPath("~/uploads"); int __maxSize = 2 * 1024 * 1024; // максимальный размер файла 2 Мб // допустимые MIME-типы для файлов List mimes = new List { "image/jpeg", "image/jpg", "image/png" }; var result = new Result { Files = new List() }; if (Request.Files.Count > 0) { foreach (string f in Request.Files) { HttpPostedFileBase file = Request.Files[f]; // Выполнить проверки на допустимый размер файла и формат if (file.ContentLength > __maxSize) { result.Error = "Размер файла не должен превышать 2 Мб"; break; } else if (mimes.FirstOrDefault(m => m == file.ContentType) == null) { result.Error = "Недопустимый формат файла"; break; } // Сохранить файл и вернуть URL if (Directory.Exists(__filepath)) { Guid guid = Guid.NewGuid(); file.SaveAs($@"{__filepath}\{guid}.{file.FileName}"); result.Files.Add($"/uploads/{guid}.{file.FileName}"); } } } return Json(result); } } public class Result { public string Error { get; set; } public List Files { get; set; } } }

    Здесь мы получаем файлы из индексатора Files объекта HttpRequestBase , который доступен в контроллере ASP.NET через свойство Request. Далее мы выполняем две простые проверки – размер файла не должен превышать 2 Мб и тип файлов должен быть либо JPG либо PNG. В случае несоответствия файла проверкам в скрипт возвращается объект с ошибкой, которая отображается пользователю. Иначе файл сохраняется в папке uploads проекта, ему присваивается сгенерированное с помощью GUID случайное имя.

    Перед тестированием данного примера не забудьте добавить в корень проекта папку uploads.