1. 程式人生 > >前端頁面檔案拖拽上傳模組html/css/js程式碼示例

前端頁面檔案拖拽上傳模組html/css/js程式碼示例

最近給衛生局做一個表格上傳/視覺化系統,算是小有成果。今天把專案中的檔案拖拽上傳模組分離出來,做了一個獨立的小demo,並把相關程式碼打包上傳到了我的github中,為了其他學習者和開發者提供拙見。

由於程式碼中我的註釋很詳盡,所以具體邏輯實現及不介紹了,大家直接看程式碼及能明白。現在簡單列一個功能清單和一些用到的知識點清單:

  1. 模態框
  2. 檔案的批量上傳
  3. 使用formData API 封裝資料 並通過ajax方法提交
  4. 讀取拖放檔案,ondrop事件 dataTransfer物件
  5. 清空所有檔案

知識點:

  1. 單例模式:構建一個單例模式的formData容器
  2. 事件冒泡,事件委託:動態新增刪除單個檔案的方法
  3. css各種佈局,BFC
  4. CSS 偽類 link vistied hover active
  5. html 離線操作文件:建立fragment 離線操作,提高效能,減少瀏覽器的重繪和迴流
  6. 原型鏈,原型方法:為formData物件新增一個刪除所有檔案的方法
  7. 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='';
}