html5 javascript拖曳物件 - 將文件拖放到標準的html文件輸入中





drag and (9)


我知道Chrome中的一些技巧。

將文件拖放到拖放區時,您將獲得一個dataTransfer.files對象,即一個“FileList”類型的對象,其中包含您拖動的所有文件。 同時,元素具有屬性“文件”,即相同的“FileList”類型對象。

因此,您可以簡單地將dataTransfer.files對象分配給input.files屬性。

現在我們可以將文件拖放到一個特殊的容器中,然後用XHR 2上傳它們。 現場進度條等非常酷的東西。 示例在這裡。

但有時我們不想要那麼多涼意。 我想要的是將文件拖放到一個標準的HTML文件輸入中<input type=file multiple>

那可能嗎? 有沒有什麼方法可以用文件放置中的正確文件名(?)“填充”文件輸入? (完整的文件路徑不適用於文件系統安全原因。)

為什麼? 因為我想提交正常表單。 適用於所有瀏覽器和所有設備。 拖放只是漸進式增強,以增強和簡化用戶體驗。 標准文件輸入(+ multiple屬性)的標準表單將在那裡。 我想添加HTML5增強功能。

編輯
我知道在某些瀏覽器中, 有時 (幾乎總是)可以將文件放入文件輸入本身。 我知道Chrome通常會這樣做,但有時會失敗,然後將文件加載到當前頁面中(如果您填寫了表單,則會導致嚴重失敗)。 我想傻瓜式和瀏覽器式的。




我為此做了一個解決方案。

$(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; 文件輸入只能看到,所以你可以看到發生了什麼。




@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();

工作小提琴




以下作品在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處理程序 - 這只是為了簡潔起見。




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




幾年後,我建立了這個庫來將文件放入任何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();



對於僅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修改




理論上,您可以添加一個覆蓋<input/>的元素,然後使用它的drop事件來捕獲文件(使用File API)並將它們傳遞給輸入files數組。

除了文件輸入是只讀的 。 這是一個老問題。

但是,您可以完全繞過表單控件並通過XHR上傳(不確定對此的支持):

您也可以使用周圍區域的元素來取消Chrome中的放置事件,並防止加載文件的默認行為。

通過輸入刪除多個文件已經可以在Safari和Firefox中使用。




XML要求所有標籤都有相應的結束標籤。 所以對於沒有內容的標籤來說,有一個特殊的短手語法。

HTML5不是XML,所以它不應該提出這樣的要求。 HTML 4.01都不是。

例如,在HTML5規範中 ,所有使用br標籤的例子都使用了<br>語法,而不是。

UPD實際上, 允許使用HTML5 。 9.1.2.1,7。





html5 file-upload drag-and-drop