我有一个定期
我想逐步增强表单,以便您可以从浏览器外部的视口中的任何位置(而不仅仅是在文件输入字段上,如某些浏览器内置的那样)删除文件以上传它。
表单是否自动提交并不重要。因此,如果拖放只选择文件字段中的文件,而不启动上载,那很好。我不需要支持多个文件。我不需要显示上传进度、缩略图或任何花哨的东西。
我知道有些JS库支持拖放上传,但它们似乎都是通过AJAX上传的。我可以这样做,但是我需要修改后端和前端来处理上传错误、重定向和显示正确的成功消息等等。
我想要一个渐进的增强,不需要任何后端更改。它应该使用页面中的表单同步发生。只要上传发生在“前台”,JS就可以了。当然,同步AJAX是行不通的。
虽然不是真正的“同步”(JavaScript执行不会真正停止),但是您可以设置
这适用于Chrome(使用jQuery):http://jsfiddle.net/qMmPr/.
$(document).on("dragover drop", function(e) {
e.preventDefault(); // allow dropping and don't navigate to file on drop
}).on("drop", function(e) {
$("input[type='file']")
.prop("files", e.originalEvent.dataTransfer.files) // put files into element
.closest("form")
.submit(); // autosubmit as well
});
感谢@pimvdb的评论,我想出了一个非常优雅的解决方案。
由于在
下面是一个演示:https://jsfiddle.net/08wbo4um
注:不幸的是,这在iframe
中似乎不起作用,但在实际页面上确实起作用。你仍然可以理解这种行为。
以下是片段:
$('input[type="file"]').on('change', function(e){
var fileName = e.target.files[0].name;
if (fileName) {
$(e.target).parent().attr('data-message', fileName);
}
});
$(document).on('drag dragstart dragend dragover dragenter dragleave drop', function(e) {
if ($('input[type="file"]').length) {
if (['dragover', 'dragenter'].indexOf(e.type) > -1) {
if (window.dragTimeout)
clearTimeout(window.dragTimeout);
$('body').addClass('dragged');
} else if (['dragleave', 'drop'].indexOf(e.type) > -1) {
// Without the timeout, some dragleave events are triggered
// when the :after appears, making it blink...
window.dragTimeout = setTimeout(function() {
$('body').removeClass('dragged');
}, 100);
}
}
});
h3, p {
text-align: center;
}
.form-group {
margin: 30px;
}
.file-upload .form-control {
height: 150px;
outline: 1px dashed #ccc;
outline-offset: -15px;
background-color: #eee;
}
.file-upload .form-control:before {
content: "\f093";
font: normal normal normal 14px/1 FontAwesome;
font-size: 3em;
left: 0;
right: 0;
display: block;
margin: 20px auto;
text-align: center;
}
.file-upload .form-control:after {
content: attr(data-message);
left: 0;
right: 0;
bottom: 0;
text-align: center;
display: block;
}
.file-upload .form-control input[type="file"] {
cursor: pointer;
opacity: 0;
width: 100%;
height: 100%;
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
}
body.dragged .file-upload .form-control input[type="file"] {
/* Make sure it is full screen, whatever the position absolute container */
position: fixed;
top: -50vh;
bottom: -50vh;
left: -50vw;
right: -50vw;
height: 200vh;
width: 200vw;
z-index: 10002;
}
body:after {
content: 'You can drop the file. :-)';
font-size: 2em;
text-align: center;
line-height: 100vh;
position: absolute;
top: 10px;
bottom: 10px;
left: 10px;
right: 10px;
background-color: #eee;
z-index: 10000;
border-radius: 4px;
border: thin solid #ccc;
visibility: hidden;
opacity: 0;
transition: visibility 0s, opacity 0.5s ease;
}
body.dragged:after {
opacity: 1;
visibility: visible;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<h3>Drag N Drop file upload without AJAX Demo</h3>
<p>Try drag and dropping a file. :-)</p>
<div class="form-group file-upload" required="required">
<label class="cols-sm-2 control-label" for="document_file">File Upload</label><br>
<div class="cols-sm-10">
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-file" aria-hidden="true"></i></span>
<div class="form-control" data-message="Click to select file or drag n drop it here">
<input required="required" title="Click to select file or drag n drop it here" type="file" name="document[file]" id="document_file">
</div>
</div>
</div>
</div>
可以通过将autoUpload设置为false,收集数组中的文件,然后在formsubmit上对所有文件和表单数据执行单个ajax调用来完成,如下所述。