드롭 파일을 표준 html 파일 입력으로 드래그


163

요즘에는 파일을 특수 컨테이너에 끌어다 놓고 XHR 2로 업로드 할 수 있습니다. 라이브 진행률 표시 줄 등. 매우 멋진 기능. 여기 예입니다.

그러나 때때로 우리는 그처럼 시원함을 원하지 않습니다. 내가 원하는 것은 드래그 앤 드롭 파일입니다 - 한 번에 많은 - 표준 HTML 파일 입력에 : <input type=file multiple>.

가능합니까? 파일 드롭에서 올바른 파일 이름 (?)으로 파일 입력을 '채우는'방법이 있습니까? 파일 시스템 보안상의 이유로 전체 파일 경로를 사용할 수 없습니다.

왜? 일반 양식을 제출하고 싶습니다. 모든 브라우저 및 모든 장치에 적용됩니다. 드래그 앤 드롭은 UX를 향상 및 단순화하기 위해 점진적으로 향상되었습니다. 표준 파일 입력 (+ multiple속성)이있는 표준 양식 이 있습니다. HTML5 향상 기능을 추가하고 싶습니다.

편집
내가 알고있는 몇 가지 브라우저 작업을 수행 할 수 있습니다 가끔 (거의 항상) 파일 입력 자체에 파일을 놓습니다. Chrome은 일반적 으로이 작업을 수행하지만 때로는 실패하고 현재 페이지에 파일을로드합니다 (양식을 작성하면 큰 실패). 나는 바보와 브라우저 증거를하고 싶다.


1
호환성에 mac / safari를 포함 시키려면 약간의 고통을 준비하십시오.
Shark8

1
@ Shark8 실제로 Safari / Mac은 이미 이것을 지원하는 몇 안되는 브라우저 중 하나입니다.
Ricardo Tomasi

실제로, 어떤 브라우저도 이것을 지원하지 않습니다. 파일 입력 필드는 읽기 전용 (보안을 위해)이며 이것이 문제입니다. 바보 같은 보안!
Rudie

2
하여 난 "- 한 번에 많은 - 표준 HTML 파일 입력에 드래그 앤 드롭 파일"을 의미했다.
Ricardo Tomasi

3
input type="file" multipleSafari에서 여러 파일을 드래그 앤 드롭
Lloyd

답변:


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>

addEventListenerevt 핸들러를 등록 하기 위해 또는 jQuery 등 을 사용하고 싶을 것입니다 .


3
와아 아아아! 작동합니다!? 그건 정확히 내가 무엇을 찾고 있었다. 2 년 전에는 작동하지 않았습니다. 대박! 물론 그것은 IE에서 작동하지 않습니다 =) 중요한 질문 : 신뢰할 수있는 기능 감지가 있습니까? 그래서 IE에서 dropzone을 숨길 수 있습니다 .bc 작동하지 않습니다.
Rudie

D' oh, 조금 늦었다 :) 지금 JS에서 간단한 사용자 에이전트 검사를 사용하고 있습니다. 물론 MSIE , Trident/(IE11) 및 Edge/(IE12) 를 테스트해야합니다 .
jlb

FF 48.0.2 (Mac)에서 "TypeError : 게터 만있는 속성 설정"이 line에 발생 fileInput.files = evt.dataTransfer.files;합니다. 그러나 Safari와 Chrome은 모두 잘 작동합니다.
Risadinha

2
이 예제는 Linux의 firefox 45에서는 작동하지 않지만 크롬에서는 작동합니다. 콘솔 오류가 발생하지 않으며 파일이 삭제되었음을 나타내지 않습니다.
Bryan Oakley

1
실제로 나는 해결책을 찾기 위해 게시물을 만들었지 만 스스로 알아 냈습니다. 아주 간단한 변경, 그냥 fileInputs [index] = ... 파일 데이터를 특정 입력으로 전달한 다음 showNext 함수를 호출하여 새 입력 추가 stackoverflow.com/a/43397640/6392779
nick

51

나는 이것에 대한 해결책을 만들었다.

이 방법의 드래그 앤 드롭 기능은 Chrome, Firefox 및 Safari에서만 작동합니다. (IE10과 호환되는지는 모르겠지만) 다른 브라우저의 경우 "또는 여기를 클릭하십시오"단추가 제대로 작동합니다.

입력 필드는 파일을 특정 영역 위로 드래그 할 때 마우스를 따라 가며 버튼도 추가했습니다.

주석 해제 불투명도 : 0; 파일 입력 만 표시되므로 진행 상황을 확인할 수 있습니다.


그렇기 때문에 버튼도 추가했습니다. ^^ 그러나 맞습니다. 나는 그것을 더 이상 사용하지 않을거야 ... 아니면 내가!?
BjarkeCK

나는 그것이 어떻게 작동 해야하는지 알고 싶습니다 ... 모든 드래그 / 드롭 기능이 호버 효과를 추가 해야하는 것처럼 보이지만 실제로는 말할 수 없습니다. 바이올린에서는 좋아 보이지만 Internet Explorer를 지원해야하므로 사용할 수 없다고 생각합니다.
nmz787

1
@PiotrKowalski 콜 스택이 넘칠 때까지 재귀 호출을 유발할 수 있다고 생각합니다.
John

2
나는 스타일 만 사용했다. 입력을 100 % 너비와 높이로 이동하면 이동하는 것보다 낫습니다.
Eddie

2
마우스 포인터와 함께 떠 다니는 "선택된 파일 없음"을 제거하는 방법이 있습니까? @BjarkeCK
Abhishek Singh

27

이것이 "DTHML"HTML5 방식입니다. 일반 양식 입력 (Ricardo Tomasi가 지적한 대로만 읽음). 그런 다음 파일을 끌어다 놓으면 양식에 첨부됩니다. 이 방법으로 업로드 된 파일을 승인하려면 작업 페이지를 수정해야합니다.

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>

전체 창을 놓기 영역으로 만들 수 있다면 더 보스입니다. Gmail처럼 창에 들어오고 나가는 HTML5 드래그 이벤트를 어떻게 감지합니까?를 참조하십시오.


1
좋은 해결책은 IE 9 이하에서 HTML5 파일을 지원하지 않기 때문에 IE <10에서는 작동하지 않습니다. API :(
Develoger

1
이 줄 : document.getElementById ( 'fileDragData'). value = files [i] .slice (); reader.onload 함수로 대체되었으므로 필요하지 않습니다.
kurdtpage

다음은 파일 업로드와 관련이없는 또 다른 귀여운 드래그 앤 드롭 응용 프로그램입니다. 누군가가 더 공부하고 싶어하는 경우를 대비하여 연결합니다. codepen.io/anon/pen/MOPvZK?editors=1010
William Entriken 2018

1
IE 10 솔루션은 성능을 저하시키는 것입니다.input type=file
William Entriken

.valuefor 루프를 반복 할 때마다 무언가가 누락되었거나 최신 파일로 속성을 지속적으로 덮어 쓰십니까?
케빈 버크

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 실행 코드 스 니펫을 클릭하고 이미지를 드래그 앤 드롭하여 이미지를 미리보기하면 드롭 된 이미지의 미리보기가 표시됩니다.
Dipak

6

이론적으로을 오버레이하는 요소를 추가 한 <input/>다음 해당 drop이벤트를 사용하여 파일을 캡처하고 (File 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.filesA는 객체, FileList당신이 끌고있는 모든 파일이 포함 된 개체의 유형을. 한편 <input type="file" />element는 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 : Chrome에서이 코드를 사용할 때 'addEventListener'속성을 읽을 수 없습니다. Chrome에서 최신 버전의 Chrome에서는 작동하지 않습니까?
불로 불 싸움

최신 버전의 Chrome에서 제대로 작동합니다. 올바른 ID를 사용해야합니다
Michael

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
참고 : 바이올린 연결이 끊어졌습니다.
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에 대해 더 많은 파일 입력을 동적으로 작성하여 추가 파일을 처리하도록하십시오. 동일한 기본 이름을 사용하고 값 속성을 적절하게 채 웁니다.

마지막으로 (프런트 엔드) 양식을 제출하십시오.


이 방법을 처리하는 데 필요한 것은 파일 배열을 처리하도록 프로 시저를 변경하는 것입니다.


1
multiple요즘 파일 입력에는 속성이 있습니다. 하나 이상의 파일 입력이 필요하지 않습니다. 그래도 문제는 아닙니다. File객체를 파일 입력으로 가져 오려면 어떻게합니까 ? 이 코드 예제가 필요하다고 생각합니다 ...
Rudie

1
@Rudie 당신은 할 수 없습니다, 그게 문제입니다.
Ricardo Tomasi

1
무엇을 할 수 없습니까? 배수? 그래 넌 할수있어. 나는 방금 말했다. 배수는 문제가되지 않습니다. (드래그 된) File 객체에서 파일을 파일 입력으로 가져 오는 것이 문제입니다.
Rudie

@Rudie는 Chrome / FF ( files속성 사용)를 사용하여 파일을 파일 입력으로 드래그하는 것이 가능 하지만 IE에서 관리하지 않았습니다. 행운이 있었습니까?
jlb

1
@jlb "파일 속성 사용"은 무엇을 의미합니까? 관련 코드로 답변을 해 주시겠습니까? 내가 찾던 것이 어떤 브라우저에서도 작동하지 않습니다.
Rudie
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.