перетащите файлы в стандартный HTML-файл - PullRequest
135 голосов
/ 04 ноября 2011

В наши дни мы можем перетаскивать файлы в специальный контейнер и загружать их с помощью XHR 2. Многие за один раз.С живыми прогресс-барами и т. Д. Очень классные вещи. Пример здесь.

Но иногда мы не хотим такой крутости.Я хотел бы перетащить файлы - по нескольку одновременно - в стандартный ввод HTML-файла : <input type=file multiple>.

Возможно ли это?Есть ли способ «заполнить» файл ввода правильными именами файлов (?) Из файла drop?(Полные пути к файлам недоступны по соображениям безопасности файловой системы.)

Почему? Поскольку я хотел бы отправить обычную форму.Для всех браузеров и всех устройств.Перетаскивание - это просто прогрессивное усовершенствование для улучшения и упрощения UX.Там будет стандартная форма со стандартным вводом файла (атрибут * multiple).Я хотел бы добавить улучшение HTML5.

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

Ответы [ 12 ]

47 голосов
/ 16 августа 2016

Следующее работает в 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;
  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 - это просто для краткости.

46 голосов
/ 03 октября 2012

Я сделал решение для этого.

$(function () {
    var dropZoneId = "drop-zone";
    var buttonId = "clickHere";
    var mouseOverClass = "mouse-over";

    var dropZone = $("#" + dropZoneId);
    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");
    document.getElementById(dropZoneId).addEventListener("dragover", function (e) {
        e.preventDefault();
        e.stopPropagation();
        dropZone.addClass(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);

    if (buttonId != "") {
        var clickZone = $("#" + buttonId);

        var oleft = clickZone.offset().left;
        var oright = clickZone.outerWidth() + oleft;
        var otop = clickZone.offset().top;
        var obottom = clickZone.outerHeight() + otop;

        $("#" + buttonId).mousemove(function (e) {
            var x = e.pageX;
            var y = e.pageY;
            if (!(x < oleft || x > oright || y < otop || y > obottom)) {
                inputFile.offset({ top: y - 15, left: x - 160 });
            } else {
                inputFile.offset({ top: -400, left: -400 });
            }
        });
    }

    document.getElementById(dropZoneId).addEventListener("drop", function (e) {
        $("#" + dropZoneId).removeClass(mouseOverClass);
    }, true);

})
#drop-zone {
    /*Sort of important*/
    width: 300px;
    /*Sort of important*/
    height: 200px;
    position:absolute;
    left:50%;
    top:100px;
    margin-left:-150px;
    border: 2px dashed rgba(0,0,0,.3);
    border-radius: 20px;
    font-family: Arial;
    text-align: center;
    position: relative;
    line-height: 180px;
    font-size: 20px;
    color: rgba(0,0,0,.3);
}

    #drop-zone input {
        /*Important*/
        position: absolute;
        /*Important*/
        cursor: pointer;
        left: 0px;
        top: 0px;
        /*Important This is only comment out for demonstration purposes.
        opacity:0; */
    }

    /*Important*/
    #drop-zone.mouse-over {
        border: 2px dashed rgba(0,0,0,.5);
        color: rgba(0,0,0,.5);
    }


/*If you dont want the button*/
#clickHere {
    position: absolute;
    cursor: pointer;
    left: 50%;
    top: 50%;
    margin-left: -50px;
    margin-top: 20px;
    line-height: 26px;
    color: white;
    font-size: 12px;
    width: 100px;
    height: 26px;
    border-radius: 4px;
    background-color: #3b85c3;

}

    #clickHere:hover {
        background-color: #4499DD;

    }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="drop-zone">
    Drop files here...
    <div id="clickHere">
        or click here..
        <input type="file" name="file" id="file" />
    </div>
</div>

Функция перетаскивания для этого метода работает только с Chrome, Firefox и Safari.(Не знаю, работает ли он с IE10), но для других браузеров кнопка «Или нажмите здесь» работает нормально.

Поле ввода просто следуйте за вашей мышью при перетаскивании файла над областью, и яТакже добавлена ​​кнопка ..

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

26 голосов
/ 08 апреля 2013

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

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?

8 голосов
/ 29 июня 2014

//----------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:180px; 
    border: 10px dashed #ccc;
}

#holder.hover { 
    width:400px; 
    height:180px; 
    border: 10px 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="500" height="180" style="width:500px; height:180px; border: 10px dashed #7A97FC;" class=" hidden"/>
        </div>
      </form>
    </body>
</html>
6 голосов
/ 14 ноября 2011

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

За исключением того, что ввод файла только для чтения .Это старая проблема.

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

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

Удалениенесколько файлов поверх ввода уже работают в Safari и Firefox.

4 голосов
/ 17 февраля 2017

Я знаю, что некоторые хитрости работают в Chrome:

При перетаскивании файлов в зону перетаскивания вы получаете объект dataTransfer.files, тип объекта FileList, который содержит все перетаскиваемые файлы.Между тем, элемент <input type="file" /> имеет свойство files, то есть тот же объект типа FileList.

Таким образом, вы можете просто присвоить объект dataTransfer.files свойству input.files.

3 голосов
/ 22 июля 2017

Для решения только для 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

2 голосов
/ 04 июля 2018

Для тех, кто хочет сделать это в 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;
    }
});

И все.

1 голос
/ 08 апреля 2018

Несколько лет спустя я построил эту библиотеку для перетаскивания файлов в любой элемент 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();
1 голос
/ 29 июля 2016

Потрясающая работа @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();

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

...