it-roy-ru.com

перетащите файлы в стандартный HTML-файл

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

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

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

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

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

127
Rudie

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

$(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; ввод файла виден только для того, чтобы вы могли видеть, что происходит.

44
BjarkeCK

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

37
jlb

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

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?

26
William Entriken

//----------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>

8
Dipak

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

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

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

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

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

6
Ricardo Tomasi

Я знаю некоторые хитрости в Chrome. 

Когда вы помещаете файлы в зону удаления, вы получаете объект dataTransfer.files, который представляет собой объект типа «FileList», который содержит все файлы, которые вы перетащили. Между тем, элемент имеет свойство «файлы», то есть тот же объект типа «FileList».

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

3
Timur Gilauri

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

3
Jonathan

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

Работает Fiddle

1
Mr_Green

Несколько лет спустя я собрал эту библиотеку для перетаскивания файлов в любой элемент 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
Joel Hernandez

Для тех, кто хочет сделать это в 2018 году, у меня есть намного лучшее и более простое решение, чем все старые вещи, размещенные здесь. Вы можете создать красивый перетаскивающий блок, используя только Vanilla 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
Michael

Это то, что я вышел. 

Использование 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>

0
Lionel Yeo