Я зрозумів (коли дивився себе), що є багато демонстрацій і навчальних посібників, які показують вам, як перетягнути файл у браузер, а потім відтворити його на сторінці. Вони часто позначаються як "перетягування та завантаження", але насправді вони не завантажуються. Цей підручник зробить вам цей останній крок.
Я проведу вам приклад, з який ви можете грати: перетягніть файл на веб-сторінку, і він буде завантажений на сервер миттєво.
Завдання #
Давайте роз розбивемо цей процес на конкретні завдання:
- Захопіть подію падіння і прочитайте її дані.
- Опублікувати ці двійкові дані на сервері.
- Надайте відгук про хід завантаження.
- За бажанням можна переглянути, що завантажується, і його статус.
Щоб досягти всього цього, нам потрібні наступні API HTML5 та не HTML5:
Майте на увазі, що не всі браузери підтримують всю цю технологію сьогодні, але вони наближаються. Я просто хотів створити чіткий і повний підручник про те, як піти весь кабанчик і завантажити, що впав файл.
Кінцевий результат: ми можемо скинути файл у будь-якому місці веб-переглядача, ми отримуємо попередній перегляд і хід завантаження, і це слизький досвід.

Перетягування зі оком #
Так само, як передвиливий, перетягування, як відомо, трохи вбиває. Насправді, це кошмар, але я не буду повторювати те, що було сказано раніше.
Наш приклад дозволить вам перетягнути файл в будь-яке місце в браузері. Щоб досягти цього, нам потрібно приєднати наших слухачів подій до
тіла
або
документаElement
(тобто кореневий HTML-вузол). Прослуховуючи доку
мент, цей код
може бути будь-де на сторінці, оскільки доку
ментОцінює зав
жди буде існувати. Ви можете слухати тільк
и на
тілі, як
тільки
<body>виявлено елемент.</body>
Ось шаблон коду, який нам потрібен, щоб зафіксувати подію падіння на весь документ:
var doc = document.documentElement; doc.ondragover = функція () { this.classНайменування = "hover";return false; }; doc.ondragend = функція () { this.className = '; returnfalse; }; doc.ondrop = функція (подія) { event.preventDefault & event.preventDefault(); this.className = ''; тепер зробіть щось з: var файли = event.dataTransfer.files; повернення false; };
Я використовую
клас
наведення, щоб я міг перемикати підказку, пояснюючи користувачеві, що файл може бути скинуто на сторінку.
Усередині по
дії п
адіння ми можемо отримати доступ до скинутих файлі
в viaevent.dataTransfer.file
s.
Альтернатива перетягування #
Набридливо, коли я пишу це, я розумію, що це поєднання вимог API в даний час відповідає тільки Chrome і Firefox. Отже, проймачи тест від Modernizr, ми можемо протестувати на підтримку та надати нашу альтернативу:
var dndПідтримувана = функція () { var div = document.createElement('div'); return (« перетягування » у div) || ('ondragstart' у div &'ondrop' у div); }; if (!dndSuped()) { // прийняти альтернативний маршрут }
Замість перетягування ми можемо вставити елемент вводу файлу (я дав йому іде
нт
ифікатор "upload"), а при зміні його значення файл можна зачерпувати в:
document.getElementById('upload').onchange = функція (подія){ // 'this' посилається на елемент події, що відбувається у файлах var = this.files; };
Ви можете побачити, що еквівалент – це про
сто в
ластивість файлів
об'єктаHTMLInpu
tElement. Це дасть нам доступ до того ж файлу, що і
event.dataTransfer.f
iles з події drop.
Автоматичне передавання файлу #
Це акуратний біт, і це болісно просто. Ми використовуємо функцію специфікації XHR
2: FormDat
a. Як тільки ми створимо екземпляр For
mData, ми
можемо додавати до нього елементи:
var formData = нові дані форми(); Для (var i = 0; i < files.length; i++) { formData.append('file', fi[i]les); } // now post a new XHR request var xhr = new XMLHttpRequest(); xhr.open('POST', '/upload'); xhr.onload = function () { if (xhr.status === 200) { console.log('all done: ' + xhr.status); } else { console.log('Something went terribly wrong...'); } }; xhr.send(формаДані);
аних форми
Так, †
Давайте подивимося на кілька ключових речей, які йдуть на вище код.
formData.append('файл', файли[i]);
Ми відправляємо іменовані параметри на наш сервер, зокрема масив значень, що називаються ф
айло
м. Очевидно, ви можете назвати це тим, що ви хочете, а
ле ф
айл – це ім'я, яке ваш сервер буде шукати, коли він зберігає завантажений файл (або файли).
xhr.onload = функція () { if (xhr.status === 200) { консоль.log('all done: ' + xhr.status); } else { консоль.log ('Щось пішло жахливо не так ...'); } };
Якщо ви знайомі з XHR, ви помітите, що ми не слухаємоназ
амін, тільки onl
oad –
яка є
(по суті) функцією зручності, щоб повідомити вам, коли readySt
ate 4 (т
обто завантажений!). Ви все одно повинні перевірити і належним чином відповісти на код стану запиту, щоб переконатися, що це 200 ОК, а не 500 (внутрішня помилка сервера) або 404 (не знайдено) або що-небудь ще.
xhr.send(формаДані);
Приємним трюком тут є те, що XHR автоматично встановив кодування опублікованих даних на багат
очастині / форми-дан
і. Це кодування дозволяє серверу читати та зберігати файли. Це схоже на кодування, яке використовується під час надсилання вкладення в повідомленні електронної пошти.
Надання зворотного зв'язку користувачеві #
XHR2 тепер (flippin' нарешті) поставляється з
подією п
рогресу. Так що якщо ви посилаєте або оголення великого файлу через XHR, ви можете сказати користувачеві, як далеко ви.
Це досить просто. Якщо ви хочете відстежувати хід запиту XHR, прослухайте по
дію про
гресу. Один gotcha, який зловив мене протягом деякого часу: мені потрібно було відслідковувати хід завантаження, а не завантаження. Щоб зробити це належним чином, вам потрібно прослухати прогрес на об'єкті завантаженняXHR, як так:
xhr.upload.onprogress = функція (подія) { if (event.lengthComputable) { var complete = (event.loaded / event.total * 100 | 0); прогрес.значення = прогрес.innerHTML = завершено; } }; xhr.onload = функція () { // про випадок, якщо ми застрягли навколо 99% progress.value = progress.innerHTML = 100; };
єю прогре
су XHR2Зверніть увагу, що замість
xhr.onprogress м
и використ
овуємоxhr.upload.onproges
s. Коли ця подія загостріться, ми перевіряємо, чи підтримує подія розрахунок обсягу завантажених даних (thel
engthComputable p
art), а потім розраховуємо суму, що була завершена.
У моєму HTML я використову
ю елемент <
progress>(схожий на<meter>
елемент,
але більш семантично</meter> </progress> доречний, коли ми представляємо хід виконання завдання), щоб показати користувачеві, скільки їх файлів було завантажено:
<progress id="progress" min="0" max="100" value="0">0</progress>
Зверніть увагу, що я викор
истовую inne
rHTML для браузерів, які ще не підтримують<progre
ss>.</progres
s> Тоді з тире CSS-створеного контенту, як theinne
rHTML, та
к і
значе
ння прогресу може бути однаковим (можливо, надмірна оптимізація, але я досить пишався собою в той час!).
І, нарешті, візуалізація попереднього перегляду #
Як приємне доповнення, ми надамо користувачеві попередній перегляд того, що ми завантажуємо для них. Для цього потрібен API файлів — зокрема
APIFileRe
ader.
Оскільки операція перетягування (або
вхідн[type=file]
і дані) містить файловий об'єкт, ми можемо передати
це в FileR
eader, щоб отримати вміст файлу. Якщо це щось на зразок зображення, ми можемо отримати дані Base64 і дати користувачеві попередній перегляд. Або, якщо це текст, ми могли б відтворити його в<div
>.</di
v> Тип MIME для файлу доступний як властив
іст
ь type для об'єкта файлу.
Отже, припустимо, що ми приймаємо тільки зображення. Ось частина попереднього перегляду, яка запускається після отримання файлу браузером:
var acceptedTypes = { 'image/png': true, 'image/jpeg': true, 'image/gif': true }; if (acceptedTypes === tru[file.type]e) { var reader = new FileReader(); reader.onload = функція (подія) { var зображення = нове зображення(); image.src = event.target.result; image.width = 100; підроблений документ зміни розміру.body.appendChild(зображення); }; reader.readAsDataURL(файл); }
Ми створюємо F
ileReader
і даємо йому файл для читання. У наведеному вище прикладі я використовував
readAsDataURL, ал
е ви також можете читати файли у форматі звичайного тексту та двійковому форматі (відповідно до специфікації).
Коли читач прочитав файл і дані доступні, він завантажить подію, яка
, в
свою чергу, створює наше нове зображення.
Результат дії з читання файлу – у файлі e
vent.target.result
property. У випадку readAsD
ataURL значе
ння знаходиться вздовж рядків да
них:image/png;base64,ABC...
.
Використання всіх інструментів у сараї #
Цей приклад може бути трохи надуманий для статті, яку я хотів написати. Я використав багато різних технологій, щоб зробити те, що є досить поширеним шаблоном в Інтернеті. Справді, це було тому, що у мене були проблеми з пошуком остаточного джерела для завантаження на фактичний сервер (за винятком, звичайно, як я написав цю статтю я знайшов цей приклад ще в кінці 2010 року!).
Сподіваюся, ви побачите, як кожен біт технологій може працювати разом, щоб створити додаток, але в рівній мірі я сподіваюся, що ви можете побачити, де це буде працювати, якщо ніхто або просто деякі технології не були доступні. Переконайтеся, що ви виявите функціональність. Переконайтеся, що ви надаєте зворотні зміни. Переконайтеся, що ви розробляєте відповідально.
Ось останнє перетягування і завантаження демонстрації для вас грати.