перетягуйте файли, що випадають, у стандартний HTML-файл


163

У ці дні ми можемо перетягувати файли в спеціальний контейнер і завантажувати їх за допомогою XHR 2. Багато за один раз. З живими прогрес-барами тощо. Дуже класні речі. Приклад тут.

Але іноді ми не хочемо такої прохолоди. Те , що я хотів би , щоб перетягнути і падіння файлів - багато в той час - в стандартне введення HTML файлу : <input type=file multiple>.

Це можливо? Чи є спосіб «заповнити» вхід файлу правильними іменами файлів (?) Від краплі файлу? (Повна безпека файлів недоступна з міркувань безпеки файлової системи.)

Чому? Тому що я хотів би подати нормальну форму. Для всіх браузерів і всіх пристроїв. Перетягування - це лише прогресивне вдосконалення для покращення та спрощення UX. Стандартна форма зі стандартним введенням файлу (+ multipleатрибут) буде там. Я хотів би додати розширення HTML5.

редагувати
Я знаю, що в деяких браузерах ви можете іноді (майже завжди) передавати файли у сам файл. Я знаю, що Chrome зазвичай це робить, але іноді він не працює, а потім завантажує файл на поточну сторінку (великий збій, якщо ви заповнюєте форму). Я хочу обдурити і захистити браузер.


1
Підготуйтеся до деякого болю, якщо ви хочете включити mac / safari до своїх сумісностей.
Shark8

1
@ Shark8 фактично Safari / Mac є одним з небагатьох браузерів, які вже підтримують це.
Рікардо Томасі

Насправді, жоден із браузерів цього не підтримує. Поле введення файлів є лише для читання (для безпеки), і це проблема. Дурна безпека!
Rudie

2
Під цим я мав на увазі "перетягування файлів - багато за один раз - у стандартний HTML-файл".
Рікардо Томасі

3
перетягування декількох файлів, щоб input type="file" multipleдобре працювати в Safari
Ллойд

Відповіді:


71

Далі працює в Chrome та FF, але я ще не знайшов рішення, яке охоплює IE10 +:

// dragover and dragenter events need to have 'preventDefault' called
// in order for the 'drop' event to register. 
// See: https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Drag_operations#droptargets
dropContainer.ondragover = dropContainer.ondragenter = function(evt) {
  evt.preventDefault();
};

dropContainer.ondrop = function(evt) {
  // pretty simple -- but not for IE :(
  fileInput.files = evt.dataTransfer.files;

  // If you want to use some of the dropped files
  const dT = new DataTransfer();
  dT.items.add(evt.dataTransfer.files[0]);
  dT.items.add(evt.dataTransfer.files[3]);
  fileInput.files = dT.files;

  evt.preventDefault();
};
<!DOCTYPE html>
<html>
<body>
<div id="dropContainer" style="border:1px solid black;height:100px;">
   Drop Here
</div>
  Should update here:
  <input type="file" id="fileInput" />
</body>
</html>

Ви, ймовірно, захочете використовувати addEventListenerабо jQuery (тощо) для реєстрації ваших обробників evt - це просто заради стислості.


3
Ваааааааат! Це працює! Це саме те , що я шукав. Не працював 2 роки тому. Дивовижно! Звичайно, це не працює в IE =) Важливе питання: чи надійне виявлення функцій? Отже, ви можете приховати dropzone в IE, bc він не працюватиме.
Rudie

Да, трохи пізніше :) Зараз я просто використовую прості перевірки агентів у JS. Звичайно , ви повинні перевірити для MSIE , Trident/(IE11) і Edge/(IE12) ...
JLB

FF 48.0.2 (Mac) кидає "Рядок TypeError: встановлення властивості, у якій є лише getter" fileInput.files = evt.dataTransfer.files;. Однак Safari і Chrome працюють чудово.
Рісадінья

2
Цей приклад не працює у Firefox 45 на Linux, але він працює для chrome. Я не отримую жодних помилок консолі, це просто не показує, що будь-який файл видалений
Брайан Оуклі

1
насправді я створив пост, щоб спробувати знайти рішення, але придумав для себе. Досить проста зміна, просто fileInputs [index] = ..., щоб передати дані файлу на певний вхід, а потім зателефонувати до функції showNext, щоб додати новий вхід stackoverflow.com/a/43397640/6392779
псевдонім

51

Я прийняв рішення для цього.

Функція перетягування для цього методу працює лише з Chrome, Firefox та Safari. (Не знаю, чи працює він з IE10), але для інших браузерів чудово працює кнопка "Або натисніть тут".

Поле введення просто слідкуйте за мишкою, перетягуючи файл по області, і я також додав кнопку ..

Непрозорість відмітки: 0; вхід файлу видно лише, щоб ви могли бачити, що відбувається.


Ось чому я додав також кнопку ^^ Але так, ти маєш рацію. Я не хотів би використовувати це ніколи ... Або я б !?
BjarkeCK

Мені б хотілося, щоб я знав, як це має працювати ... здається, всі функції перетягування / падіння мають справу з додаванням ефекту наведення ... але я справді не можу сказати. Виглядає добре у скрипці, але я не думаю, що я можу це використати, оскільки мені потрібно підтримувати Internet Explorer
nmz787,

1
@PiotrKowalski Я думаю, що це потенційно може викликати рекурсивний виклик, поки стек викликів не переповниться
Джон

2
Я в кінцевому підсумку використовував лише стиль. Зробити вхід на 100% шириною та висотою краще, ніж переміщати його.
Едді

2
Чи є спосіб позбутися від "не вибраного файлу", який продовжує ширяти разом з нашим покажчиком миші? @BjarkeCK
Абхішек Сінгх

27

Це "DTHML" HTML5 спосіб зробити це. Нормальне введення форми (яке читається тільки так, як вказував Рікардо Томасі). Потім, якщо файл затягнуто, він додається до форми. Для прийняття файлу, завантаженого таким чином, буде потрібно змінити сторінку дій.

function readfiles(files) {
  for (var i = 0; i < files.length; i++) {
    document.getElementById('fileDragName').value = files[i].name
    document.getElementById('fileDragSize').value = files[i].size
    document.getElementById('fileDragType').value = files[i].type
    reader = new FileReader();
    reader.onload = function(event) {
      document.getElementById('fileDragData').value = event.target.result;}
    reader.readAsDataURL(files[i]);
  }
}
var holder = document.getElementById('holder');
holder.ondragover = function () { this.className = 'hover'; return false; };
holder.ondragend = function () { this.className = ''; return false; };
holder.ondrop = function (e) {
  this.className = '';
  e.preventDefault();
  readfiles(e.dataTransfer.files);
}
#holder.hover { border: 10px dashed #0c0 !important; }
<form method="post" action="http://example.com/">
  <input type="file"><input id="fileDragName"><input id="fileDragSize"><input id="fileDragType"><input id="fileDragData">
  <div id="holder" style="width:200px; height:200px; border: 10px dashed #ccc"></div>
</form>

Це ще більше, якщо ви можете зробити все вікно зоною випаду, див. Як я можу виявити подія перетягування HTML5, що входить і залишає вікно, як це робить Gmail?


1
Гарне рішення, але воно не працює на IE <10, тому що IE 9 і менше не підтримує API файлів HTML5 :(
Develoger

1
Цей рядок: document.getElementById ('fileDragData'). Value = files [i] .slice (); не потрібен, оскільки він заміщений у функції read.onload
kurdtpage

Ось ще одна мила програма перетягування, яка НЕ ​​передбачає завантаження файлів. Зв’язування про всяк випадок, коли хтось хоче вчитися більше. codepen.io/anon/pen/MOPvZK?editors=1010
Вільям Ентрікен

1
Рішення IE 10 полягає в деградації і показує лишеinput type=file
Вільям Ентрікен

Чи щось мені не вистачає, чи ви просто постійно переписуєте .valueвластивість найсвіжішим файлом кожного разу, коли ви повторюєте цикл переднього плану?
Кевін Берк

13

//----------App.js---------------------//
$(document).ready(function() {
    var holder = document.getElementById('holder');
    holder.ondragover = function () { this.className = 'hover'; return false; };
    holder.ondrop = function (e) {
      this.className = 'hidden';
      e.preventDefault();
      var file = e.dataTransfer.files[0];
      var reader = new FileReader();
      reader.onload = function (event) {
          document.getElementById('image_droped').className='visible'
          $('#image_droped').attr('src', event.target.result);
      }
      reader.readAsDataURL(file);
    };
});
.holder_default {
    width:500px; 
    height:150px; 
    border: 3px dashed #ccc;
}

#holder.hover { 
    width:400px; 
    height:150px; 
    border: 3px dashed #0c0 !important; 
}

.hidden {
    visibility: hidden;
}

.visible {
    visibility: visible;
}
<!DOCTYPE html>

<html>
    <head>
        <title> HTML 5 </title>
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.js"></script>
    </head>
    <body>
      <form method="post" action="http://example.com/">
        <div id="holder" style="" id="holder" class="holder_default">
          <img src="" id="image_droped" width="200" style="border: 3px dashed #7A97FC;" class=" hidden"/>
        </div>
      </form>
    </body>
</html>


2
Що він показує користувачеві? Чи можете ви зробити загадку чи приклад в Інтернеті?
Rudie

@Rudie, натисніть фрагмент запуску коду та перетягніть одне зображення для перегляду, воно покаже попередній перегляд зображення, яке випало.
Діпак

6

Теоретично, ви можете додати елемент, що накладає <input/>, а потім використовувати його dropподію, щоб захопити файли (за допомогою API файлу) та передати їх у вхідний filesмасив.

За винятком того, що вхід файлу є лише для читання . Це стара проблема.

Однак ви можете повністю обійти контроль форми та завантажити і за допомогою XHR (не впевнений у підтримці для цього):

Ви також можете використовувати елемент в околицях, щоб скасувати подію випадання в Chrome і запобігти поведінці завантаження файлу за замовчуванням.

Видалення декількох файлів на вхід вже працює в Safari та Firefox.


6
Як я вже сказав у запитанні: я знаю XHR2 і не хочу його використовувати. Я думаю, що важлива частина: "Введення файлу лише для читання". Це відстійно ... Скасування події падіння - не погана ідея! Не так добре, як я сподівався, але, мабуть, найкраще. Видалення декількох файлів працює і в Chrome. Тепер Chrome також дозволяє завантажувати каталоги. Все дуже здивовано і не допомагає моєму випадку = (
Rudie

5

Це те, з чим я вийшов.

Використання Jquery та Html. Це додасть його до вставлених файлів.

var dropzone = $('#dropzone')


dropzone.on('drag dragstart dragend dragover dragenter dragleave drop', function(e) {
    e.preventDefault();
    e.stopPropagation();
  })

dropzone.on('dragover dragenter', function() {
    $(this).addClass('is-dragover');
  })
dropzone.on('dragleave dragend drop', function() {
    $(this).removeClass('is-dragover');
  })  
  
dropzone.on('drop',function(e) {
	var files = e.originalEvent.dataTransfer.files;
	// Now select your file upload field 
	// $('input_field_file').prop('files',files)
  });
input {	margin: 15px 10px !important;}

.dropzone {
	padding: 50px;
	border: 2px dashed #060;
}

.dropzone.is-dragover {
  background-color: #e6ecef;
}

.dragover {
	bg-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<div class="" draggable='true' style='padding: 20px'>
	<div id='dropzone' class='dropzone'>
		Drop Your File Here
	</div>
	</div>


4

Тільки для рішення CSS:

<div class="file-area">
    <input type="file">
    <div class="file-dummy">
        <span class="default">Click to select a file, or drag it here</span>
        <span class="success">Great, your file is selected</span>
    </div>
</div>

.file-area {
    width: 100%;
    position: relative;
    font-size: 18px;
}
.file-area input[type=file] {
    position: absolute;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    opacity: 0;
    cursor: pointer;
}
.file-area .file-dummy {
    width: 100%;
    padding: 50px 30px;
    border: 2px dashed #ccc;
    background-color: #fff;
    text-align: center;
    transition: background 0.3s ease-in-out;
}
.file-area .file-dummy .success {
    display: none;
}
.file-area:hover .file-dummy {
    border: 2px dashed #1abc9c;
}
.file-area input[type=file]:valid + .file-dummy {
    border-color: #1abc9c;
}
.file-area input[type=file]:valid + .file-dummy .success {
    display: inline-block;
}
.file-area input[type=file]:valid + .file-dummy .default {
    display: none;
}

Змінено з https://codepen.io/Scribblerockerz/pen/qdWzJw


4

Я знаю, який трюк працює в Chrome:

При опусканні файлів у зону випадання ви отримуєте dataTransfer.filesоб'єкт, тобто FileListтип об’єкта, який містить усі файли, які ви перетягували. Тим часом <input type="file" />елемент має властивість files, тобто FileListоб'єкт одного типу.

Отже, ви можете просто призначити dataTransfer.filesоб’єкт input.filesвластивості.


3
Так, це робиться в наші дні. Не хитрість. Дуже навмисно. Також дуже навмисно дуже обмежений. Ви не можете додавати файли до списку або взагалі змінювати його. Перетягуючи та видаляючи, можна запам’ятовувати файли та додавати до них, але input.filesне може = (
Rudie

3

Для всіх, хто хоче це зробити у 2018 році, я отримав набагато краще та простіше рішення, ніж усі старі речі, розміщені тут. Ви можете зробити гарне вікно перетягування з просто ванільним HTML, JavaScript та CSS.

(Поки працює лише в Chrome)

Почнемо з HTML.

<div>
<input type="file" name="file" id="file" class="file">
<span id="value"></span>
</div>

Тоді ми перейдемо до стайлінгу.

    .file {
        width: 400px;
        height: 50px;
        background: #171717;
        padding: 4px;
        border: 1px dashed #333;
        position: relative;
        cursor: pointer;
    }

    .file::before {
        content: '';
        position: absolute;
        background: #171717;
        font-size: 20px;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        width: 100%;
        height: 100%;
    }

    .file::after {
        content: 'Drag & Drop';
        position: absolute;
        color: #808080;
        font-size: 20px;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
    }

Після того як ви це зробили, це вже виглядає чудово. Але я думаю, ви хотіли б побачити, який файл ви точно завантажили, тому ми збираємося зробити JavaScript. Пам'ятайте, що pfp-значення? Ось де ми роздрукуємо ім’я файлу.

let file = document.getElementById('file');
file.addEventListener('change', function() {
    if(file && file.value) {
        let val = file.files[0].name;
        document.getElementById('value').innerHTML = "Selected" + val;
    }
});

І це все.


Я отримую Uncaught TypeError: Неможливо прочитати властивість 'addEventListener' з null, коли я використовую цей код - під Chrome - це не працює в останніх версіях Chrome?
Боротьба з вогнем

Для мене це добре працює в останній версії Chrome. Переконайтеся, що ви користуєтеся правильними ідентифікаторами
Майкл

1

Дивовижна робота від @BjarkeCK. Я вніс деякі зміни в його роботу, щоб використовувати його як метод у jquery:

$.fn.dropZone = function() {
  var buttonId = "clickHere";
  var mouseOverClass = "mouse-over";

  var dropZone = this[0];
  var $dropZone = $(dropZone);
  var ooleft = $dropZone.offset().left;
  var ooright = $dropZone.outerWidth() + ooleft;
  var ootop = $dropZone.offset().top;
  var oobottom = $dropZone.outerHeight() + ootop;
  var inputFile = $dropZone.find("input[type='file']");
  dropZone.addEventListener("dragleave", function() {
    this.classList.remove(mouseOverClass);
  });
  dropZone.addEventListener("dragover", function(e) {
    console.dir(e);
    e.preventDefault();
    e.stopPropagation();
    this.classList.add(mouseOverClass);
    var x = e.pageX;
    var y = e.pageY;

    if (!(x < ooleft || x > ooright || y < ootop || y > oobottom)) {
      inputFile.offset({
        top: y - 15,
        left: x - 100
      });
    } else {
      inputFile.offset({
        top: -400,
        left: -400
      });
    }

  }, true);
  dropZone.addEventListener("drop", function(e) {
    this.classList.remove(mouseOverClass);
  }, true);
}

$('#drop-zone').dropZone();

Робоча скрипка


1
FYI: Fiddle посилання розірвано.
jimiayler

1

Через кілька років я створив цю бібліотеку, щоб робити файли, що впадають у будь-який HTML-елемент.

Ви можете користуватися нею

const Droppable = require('droppable');

const droppable = new Droppable({
    element: document.querySelector('#my-droppable-element')
})

droppable.onFilesDropped((files) => {
    console.log('Files were dropped:', files);
});

// Clean up when you're done!
droppable.destroy();

як пізніше вибирається вибраний файл під час подання форми?
Nikhil VJ

-1

Що ви можете зробити, це відобразити введення файлу та накласти його прозорою області випаду, обережно використовувати таке ім’я file[1]. {Не забудьте мати enctype="multipart/form-data"тег FORM всередині.}

Потім дозвольте обробляти додаткові файли, динамічно створюючи більше входів для файлів 2..number_of_files, не забудьте використовувати те саме базове ім’я, заповнивши атрибут value відповідним чином.

Нарешті (фронт) подайте форму.


Все, що потрібно для обробки цього методу - це змінити процедуру для обробки масиву файлів.


1
Введення файлу має multipleатрибут цих днів. Немає необхідності вводити більше 1 файлу. Але це не питання. Як отримати Fileоб'єкти на вхід файлу? Я думаю, для цього потрібен приклад коду ...
Rudie

1
@Rudie ти не можеш, це проблема.
Рікардо Томасі

1
Не можете що? Кілька? Так, ти можеш. Я щойно сказав це. Множина не проблема. Отримати файли з (перетягнутого) файлового об’єкта на вхід файлу, ось у чому проблема.
Rudie

@Rudie потрапляння перетягнутих (-ів) файлів (файлів) на введення файлів можливо за допомогою Chrome / FF (використовуючи filesвластивість), але я не впорався з IE - у вас виникла удача?
jlb

1
@jlb Що ви маєте на увазі "використання властивості файлів"? Не могли б ви відповісти відповідним кодом? Те, що я шукав, не працює / не існує в жодному браузері.
Rudie
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.