Перетаскивание файлов из рабочего стола в браузер одна из наиболее интересных возможностей HTML5. Я опишу как:
- сделать возможным перетаксивание файлов на элемент web страницы.
- анализировать перенесенные файлы с помошью JavaScript.
- загружать и парсить файлы со стороны клиента.
- асинхронно загружать файлы на сервер используя XMLHttpRequest2
- показать прогресс бар пока идет загрузка файлов
Поддержка браузеров
Прежде чем начать, нужно отметить что поддержка перетаскивания файлов браузерами будет неравномерной. Код работает в современных браузерах, но вполне возможно API будет меняться.
- Последние версии Firefox и Chrome поддерживают все функции и превосходно работают с перетаскиванием.
- Опера может парсить файлы в JavaScript, но не поддерживает перетаскивание файлов и загрузку с помощю XMLHttpRequuest2
- IE и десктоповые версии Safari не поддерживают ничего из нужного API.
HTML и CSS
Далее идет код стандартной формы с инпутом типа файл. Единственное HTML5 нововведение в форме это атрибут "multiple" который позволяет пользователю выбирать любое количество файлов.
Со стороны сервера загрузка файлов будет проводиться средствани PHP, но независимо от того какую технологию вы используете на сервере JavaScript код останется тем же. Скрытое поле MAX_FILE_SIZE определяет 300,000 байт, размер будем проверять и на стороне клиента и на стороне сервера, чтобы предотвротить загрузку огромного размера файлов.
<form id="upload" action="upload.php" method="POST" enctype="multipart/form-data">
<fieldset>
<legend>HTML Загрузка Файлов</legend>
<input type="hidden" id="MAX_FILE_SIZE" name="MAX_FILE_SIZE" value="300000" />
<div>
<label for="fileselect">Выберите файлы для загрузки:</label>
<input type="file" id="fileselect" name="fileselect[]" multiple="multiple" />
<div id="filedrag" >Или перетащите их сюда</div>
</div>
<div id="submitbutton">
<button type="submit">Загрузить файлы</button>
</div>
</fieldset>
</form>
Элемент #filedrag будет использоваться как облясть в которую необходимо пренести файлы. Элемент в CSS стилях скрыт, но он будет отображаться средствами JavaScript если перетаскивание поддерживается браузером:
*{
margin: 0px;
}
body{
background: none repeat scroll 0% 0% #EFEFEF;
}
.wrapper{
background: none repeat scroll 0% 0% #FFFFFF;
margin: 150px auto;
border: 2px solid #3DA8BA;
padding: 10px;
width: 500px;
}
fieldset{
border:2px solid #efefef;
}
#filedrag{
border-radius: 7px 7px 7px 7px;
border: 2px dashed #3DA8BA;
color: #555555;
cursor: default;
display: none;
margin: 1em 0pt;
padding: 1em 0pt;
text-align: center;
background:#f9f9f9;
}
#filedrag.hover {
border-style: solid;
box-shadow: 0pt 3px 4px #dbdbdb inset;
}
#messages{
margin-top:10px;
padding:5px;
font-size:14px;
}
#messages p{
border-bottom:1px solid #efefef;
margin-bottom:5px;
}
Для элемента также определенн класс .hover который меняет стили когдо пользователь перетаксивает файлы на элемент. Браузеры не поддерживают стили :hover в этой ситуации, но мы можем добовлять класс спомощю Javascript когда происходит нужное событие.
File API
W3C File API предостовляет несколько объектов которые мы будем использовать:
- FileList: предостовляет массив выбранных файлов.
- File: предстовляет единственный файл.
- FileReader: интерфейс который позволяет нам считать информацию о файле со стороны клиента и использовать в JavaScript.
JavaScript события
Пришло время писать JavaScript код. Мы не будем использовать JavaScript фреймфроков, поэтому напишем пару фуннкций для сохронения нашего времени. Это функция которая достает нужный элемент по ид и функция выводящая сообщения
/* getElementById */
function $id(id) {
return document.getElementById(id);
}
/* вывод сообщений */
function Output(msg) {
var m = $id("messages");
m.innerHTML = msg + m.innerHTML;
}
Далее проверим поддержку File API и вызовем функцию инициализации Init():
/* проверка поддержки API */
if (window.File && window.FileList && window.FileReader){
Init();
}
/* инициализация */
function Init(){
var fileselect = $id("fileselect"),
filedrag = $id("filedrag"),
submitbutton = $id("submitbutton");
/* выбор файла */
fileselect.addEventListener("change", FileSelectHandler, false);
/* проверка поддержки XHR2 */
var xhr = new XMLHttpRequest();
if (xhr.upload){
/* сброс файла */
filedrag.addEventListener("dragover", FileDragHover, false);
filedrag.addEventListener("dragleave", FileDragHover, false);
filedrag.addEventListener("drop", FileSelectHandler, false);
filedrag.style.display = "block";
/* удаление кнопки сабмитта */
submitbutton.style.display = "none";
}
}
Функция Init():
- Устонавливает обработчик события к изменению инпута типа файл.
- Отоброжает элемент #filedrag.
- Устанавливает обработчики событий "dragover" и "dragleave" для динамического изменения стилей элемента #filedrag.
- Устанавливает обработчик события "drop" для элемента #filedrag.
- Скрывает кнопку сабмитта формы - он пока не требуется, так как мы будем просто анализировать файлы.
Также вы можете скрыть инпут типа файл, если перетаскивание поддерживается. Но я не буду этого делать чтобы пользователь мог воспользоваться удобным ему вариантом.
Проверка поддержки метода XMLHttpRequest.upload предотврощает проблемы с Оперой. Браузер поддерживает объекты File, FileList и FileReader, но не поддерживает перетаскивание файлов или XMLHttpRequest2. Поэтому мы отоброжаем информацию о файле, но оставляем скрытым элемент #filedrag.
Изменение стилей при переносе
Мало кто испытал перетаскивание файлов в браузер. На самом деле, многие опытные интернет пользователи считают это невозможным. Поэтому написали внутри элемента "перетащите сюда файлы". А следующая функция будет добвлять класс к элементу, когда файл уже будет находится непосредственно над элементом, тем самым будут меняться стили.
// Файл над нужной областью
function FileDragHover(e){
e.stopPropagation();
e.preventDefault();
e.target.className = (e.type == "dragover" ? "hover" : "");
}
Анализирование перетащенных или выбранных файлов
Будем использовать функцию FileSelectHandler() не зависимо от того обин или несколько файлов были выбранны или перетащенны на элемент #filedrag:
// выбор файла
function FileSelectHandler(e){
FileDragHover(e);
// проходимся по объекту FileList
var files = e.target.files || e.dataTransfer.files;
// парсим все объекты типа File
for (var i = 0, f; f = files[i]; i++){
ParseFile(f);
}
}
Функция:
- Вызываем функцию FileDragHover() чтобы убрать стиля при hover и предотвратить выполнение событий браузера. Это очень важно, так как браузер может попытаться отобразить файл
- Проходимся по объекту FileList.
- Наконец функция проходит по всем объектам типа File в объекте FileList и передает их как аргумент в функцию ParseFile()
function ParseFile(file) {
Output(
"<p>File information: <strong>" + file.name +
"</strong> type: <strong>" + file.type +
"</strong> size: <strong>" + file.size +
"</strong> bytes</p>"
);
}
Функция выводит информация используя три основные свойства представленные объектом File только для чтения.
- .name: имя файла (не включая путь к файлу)
- .type: MIME тип, например: image/jpeg, text/plain, и т.д.
- .size: размер файла в байтах