前端頁面檔案拖拽上傳模組html/css/js程式碼示例
阿新 • • 發佈:2018-12-23
最近給衛生局做一個表格上傳/視覺化系統,算是小有成果。今天把專案中的檔案拖拽上傳模組分離出來,做了一個獨立的小demo,並把相關程式碼打包上傳到了我的github中,為了其他學習者和開發者提供拙見。
由於程式碼中我的註釋很詳盡,所以具體邏輯實現及不介紹了,大家直接看程式碼及能明白。現在簡單列一個功能清單和一些用到的知識點清單:
- 模態框
- 檔案的批量上傳
- 使用formData API 封裝資料 並通過ajax方法提交
- 讀取拖放檔案,ondrop事件 dataTransfer物件
- 清空所有檔案
知識點:
- 單例模式:構建一個單例模式的formData容器
- 事件冒泡,事件委託:動態新增刪除單個檔案的方法
- css各種佈局,BFC
- CSS 偽類 link vistied hover active
- html 離線操作文件:建立fragment 離線操作,提高效能,減少瀏覽器的重繪和迴流
- 原型鏈,原型方法:為formData物件新增一個刪除所有檔案的方法
- CSS偽物件,結合after偽物件畫一個‘X’號,放在模態框右上角表示退出按鈕
截圖:
整體介面
點選‘拖拽上傳’按鈕
拖拽檔案到虛線框,檔案拖入會邊框變紅提示
上傳成功,彈出提示
—————————-、
程式碼
1. html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="demo.css">
</head>
<body>
<!--遮罩-->
<div class="overlay"></div>
<!--模態框-->
<div id="modal" class="dropbox" >
<div class="items-container">
<div id="close" style="cursor:pointer;float: right;width:20px">
<span class="css-close"></span>
</div>
<div>
<p class="head"><b>拖拽檔案至此</b></p>
<div class="content" id="content">
<table class="table">
<tbody class="tbody"></tbody>
</table>
</div>
<div class="footer">
<button class="btn" onclick="upload()">開始上傳</button>
</div>
<a href='#' onclick='clearAll()' style='position:absolute;bottom:10px;right:30px;'>清空所有</a>
</div>
</div>
</div>
<!--頁面內容-->
<div style="margin-top:40vh;text-align: center;">
<p>拖拽上傳演示模板。點選下方按鈕,彈出模態框</p>
<button class="btn" onclick="showModal()">點選上傳</button>
</div>
<!--嵌入指令碼-->
<script src="jquery-1.10.2.js" type="text/javascript"></script>
<script src="demo.js" type="text/javascript"></script>
</body>
</html>
CSS
.overlay{
z-index: 99;
position:fixed;
display: none;
top:0;
left:0;
width: 100%;
height: 100%;
background-color: #333;
opacity:0.5;
}
.dropbox{
z-index: 100;
display: none;
position: fixed;
width:500px;
height:520px;
margin:auto;
top:0;
right:0;
bottom: 0;
left:0;
background-color: #fff;
border-radius:6px;
transition-duration: 0.9s;
-webkit-transition-duration: 0.9s;
overflow:hidden;
text-align: center;
}
.items-container{
padding: 10px;
}
.content{
border: 3px dashed gray;
border-radius: 10px;
margin: 10px 20px;
height:400px;
overflow: auto;
padding:2px 8px;
}
.head{
margin:0px;
font-size:30px;
color:#aaa;
}
.footer{
margin:5px auto
}
.btn{
border-radius: 20px;
box-sizing: border-box;
border-width: 2px;
background-color: transparent;
font-size: 14px;
font-weight: 500;
padding: 7px 18px
}
/*畫一個叉號,表示推出介面*/
.css-close{display:inline-block; width:15px; height:2px; background:#000; font-size:0; line-height:0;vertical-align:middle;-webkit-transform: rotate(45deg);}
.css-close:after { content:'.'; display:block; width:15px; height:2px; background:#000;-webkit-transform: rotate(90deg);}
/*表格樣式*/
.table{
width:100%;
border-collapse: collapse;
}
#content tr:first-child td{
border-top-width: 0px;
}
#content tr td:last-child{
cursor: pointer;
color: red;
}
#content tr td{
padding: 8px;
white-space: nowrap;
overflow: hidden;
text-overflow:ellipsis;
border-top:1px solid #9A9A9A;
}
#content tr:hover{
background-color: #d5d5d5;
}
#content tr:active{
background-color: #9A9A9A;
}
a:link{
color:blue;
}
a:visited{
color:blue;
}
a:hover{
color:blue;
}
a:active{
color:red;
}
js程式碼:
function showModal() { //開啟上傳框
var modal = document.getElementById('modal');
var overlay = document.getElementsByClassName('overlay')[0];
overlay.style.display = 'block';
modal.style.display = 'block';
}
function closeModal() { //關閉上傳框
var modal = document.getElementById('modal');
var overlay = document.getElementsByClassName('overlay')[0];
overlay.style.display = 'none';
modal.style.display = 'none';
}
//用DOM2級方法為右上角的叉號和黑色遮罩層新增事件:點選後關閉上傳框
document.getElementsByClassName('overlay')[0].addEventListener('click', closeModal, false);
document.getElementById('close').addEventListener('click', closeModal, false);
//利用html5 FormData() API,建立一個接收檔案的物件,因為可以多次拖拽,這裡採用單例模式建立物件Dragfiles
var Dragfiles=(function (){
var instance;
return function(){
if(!instance){
instance = new FormData();
}
return instance;
}
}());
//為Dragfiles新增一個清空所有檔案的方法
FormData.prototype.deleteAll=function () {
var _this=this;
this.forEach(function(value,key){
_this.delete(key);
})
}
//新增拖拽事件
var dz = document.getElementById('content');
dz.ondragover = function (ev) {
//阻止瀏覽器預設開啟檔案的操作
ev.preventDefault();
//拖入檔案後邊框顏色變紅
this.style.borderColor = 'red';
}
dz.ondragleave = function () {
//恢復邊框顏色
this.style.borderColor = 'gray';
}
dz.ondrop = function (ev) {
//恢復邊框顏色
this.style.borderColor = 'gray';
//阻止瀏覽器預設開啟檔案的操作
ev.preventDefault();
var files = ev.dataTransfer.files;
var len=files.length,
i=0;
var frag=document.createDocumentFragment(); //為了減少js修改dom樹的頻度,先建立一個fragment,然後在fragment裡操作
var tr,time,size;
var newForm=Dragfiles(); //獲取單例
var it=newForm.entries(); //建立一個迭代器,測試用
while(i<len){
tr=document.createElement('tr');
//獲取檔案大小
size=Math.round(files[i].size * 100 / 1024) / 100 + 'KB';
//獲取格式化的修改時間
time = files[i].lastModifiedDate.toLocaleDateString() + ' '+files[i].lastModifiedDate.toTimeString().split(' ')[0];
tr.innerHTML='<td>'+files[i].name+'</td><td>'+time+'</td><td>'+size+'</td><td>刪除</td>';
console.log(size+' '+time);
frag.appendChild(tr);
//新增檔案到newForm
newForm.append(files[i].name,files[i]);
//console.log(it.next());
i++;
}
this.childNodes[1].childNodes[1].appendChild(frag);
//為什麼是‘1’?文件裡幾乎每一樣東西都是一個節點,甚至連空格和換行符都會被解釋成節點。而且都包含在childNodes屬性所返回的陣列中.不同於jade模板
}
function blink()
{
document.getElementById('content').style.borderColor = 'gray';
}
//ajax上傳檔案
function upload(){
if(document.getElementsByTagName('tbody')[0].hasChildNodes()==false){
document.getElementById('content').style.borderColor = 'red';
setTimeout(blink,200);
return false;
}
var data=Dragfiles(); //獲取formData
$.ajax({
url: 'upload',
type: 'POST',
data: data,
async: true,
cache: false,
contentType: false,
processData: false,
success: function (data) {
alert('succeed!') //可以替換為自己的方法
closeModal();
data.deleteAll(); //清空formData
$('.tbody').empty(); //清空列表
},
error: function (returndata) {
alert('failed!') //可以替換為自己的方法
}
});
}
// 用事件委託的方法為‘刪除’新增點選事件,使用jquery中的on方法
$(".tbody").on('click','tr td:last-child',function(){
//刪除拖拽框已有的檔案
var temp=Dragfiles();
var key=$(this).prev().prev().prev().text();
console.log(key);
temp.delete(key);
$(this).parent().remove();
});
//清空所有內容
function clearAll(){
if(document.getElementsByTagName('tbody')[0].hasChildNodes()==false){
document.getElementById('content').style.borderColor = 'red';
setTimeout(blink,300);
return false;
}
var data=Dragfiles();
data.deleteAll(); //清空formData
//$('.tbody').empty(); 等同於以下方法
document.getElementsByTagName('tbody')[0].innerHTML='';
}