美文网首页
改写文件上传支持断点续传-前端JS代码

改写文件上传支持断点续传-前端JS代码

作者: 温暖春阳 | 来源:发表于2018-02-09 17:11 被阅读24次

    前端代码

    <!DOCTYPE html>
    <html lang="en">
     <head> 
      <meta charset="UTF-8" /> 
      <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 
      <meta http-equiv="X-UA-Compatible" content="ie=edge" /> 
      <link rel="stylesheet" href="./bootstrap/bootstrap.min.css" /> 
      <link rel="stylesheet" href="./bootstrap/bootstrap-theme.min.css" /> 
    <style>
    * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
    }
    
    body {
        background:#f5f5f5;
    }
    
    .row_input{
        width: 100%;
        max-width: 400px;
      height: 39px;
      margin: 15px auto;
      background: #fefefe;
      border: 1px solid #cecece;
      font-size: 12px;
      font-family: sans-serif;
      color: #888;
      border-radius: 4px;
      cursor: pointer;
      overflow: hidden; 
      padding:0!important;
      position:relative;
    }
    
    .input-caption{
      display: block;
      height: 100%;
        line-height:36px;
      padding-left: 10px;
      text-overflow: ellipsis;
      overflow: hidden;
      font-size:14px;
      font-weight: normal;
      padding-right:100px
    }
    .close_btn{
        width:100%;
        margin:0 auto;
        max-width:400px;
        display: block;
        height: 100%;
        padding:0;
        border: 1px solid #ccc;
        line-height: 36px;
        border-radius: 4px;
        color: #666666;
        margin-top: 15px;
        text-align: center;
        background-color: #fefefe;
        background-image: -webkit-gradient(linear,0 0,0 100%,from(#fefefe),to(#f1f1f1));
        background-image: -webkit-linear-gradient(top,#fefefe,#f1f1f1);
        background-image: -o-linear-gradient(top,#fefefe,#f1f1f1);
        background-image: linear-gradient(to bottom,#fefefe,#f1f1f1);
        background-image: -moz-linear-gradient(top,#fefefe,#f1f1f1);
        -webkit-transition: all .1s ease-out;
        -moz-transition: all .1s ease-out;
        -o-transition: all .1s ease-out;
        transition: all .1s ease-out;   
        cursor:pointer
        }
    .input-button{
        position:absolute;
        right:0;
        top:0;  
        display: block;
        height: 100%;
        padding:0;
        border-left: 1px solid #ccc;
        color: #666666;
        text-align: center;
        background-color: #fefefe;
        background-image: -webkit-gradient(linear,0 0,0 100%,from(#fefefe),to(#f1f1f1));
        background-image: -webkit-linear-gradient(top,#fefefe,#f1f1f1);
        background-image: -o-linear-gradient(top,#fefefe,#f1f1f1);
        background-image: linear-gradient(to bottom,#fefefe,#f1f1f1);
        background-image: -moz-linear-gradient(top,#fefefe,#f1f1f1);
        -webkit-transition: all .1s ease-out;
        -moz-transition: all .1s ease-out;
        -o-transition: all .1s ease-out;
        transition: all .1s ease-out;   
        cursor:pointer
    }
    
    .wrap {
        width: 100px;
        height: 36px;
        background-color: red;
        text-align: center;
        border-radius:0;
        border:0;
        padding:0;
    }
    
    .wrap p {
        width: 100%;
        height: 100%;
        line-height: 36px;
        text-align: center;
    }
    
    #file {
        position: absolute;
        left: 0;
        top: 0;
        width: 100px;
        height: 36px;
        display: block;
        opacity: 0;
    }
    
    .progress {
        position: relative;
    }
    
    .progress-bar {
        transition: width .3s ease
    }
    
    .progress .value {
        position: absolute;
        color: #FF9800;
        left: 50%;
    }
    
    .container {
        width: ;
    }
    
    .container label{
        display:block;
        cursor:pointer;
        }
    
    .row {
        padding: 10px;
        margin:0;
    }
    
    .hidden {
        display: none;
    }
    
    .loading_pro{
        margin:0 auto;
        max-width:400px;
        border: 1px solid #C5C5C5;
        box-shadow: 0 0 3px #ccc;
        -webkit-box-shadow: 0 0 3px #ccc;
        background:white;
        margin-top:15px;
        padding-bottom:10px;
        }
    .loading_pro h5{
        text-align:center;
        line-height:24px;
        font-size:16px;
        margin-bottom:0;
        }
        
    .dotting {
        display: inline-block; width: 10px; min-height: 2px;
        padding-right: 2px;
        border-left: 2px solid currentColor; border-right: 2px solid currentColor;   
        background-color: currentColor; background-clip: content-box;
        box-sizing: border-box;
        animation: dot 4s infinite step-start both;
        *zoom: expression(this.innerHTML = '...'); /* IE7 */
    }
    .dotting:before { content: '...'; } /* IE8 */
    .dotting::before { content: ''; }
    :root .dotting { margin-left: 2px; padding-left: 2px; } /* IE9+ */
    
    @keyframes dot {
        25% { border-color: transparent; background-color: transparent; }          /* 0个点 */
        50% { border-right-color: transparent; background-color: transparent; }    /* 1个点 */
        75% { border-right-color: transparent; }                                   /* 2个点 */
    }
    </style> 
      <title>上传文件</title> 
     </head> 
     <body> 
      <div class="container"> 
    
      
        
       <label for="file">
        <div class="row_input"> 
            <div class="input-caption" id = "input-caption">
             选择文件上传
            </div> 
            <div class="input-button"> 
             <div class="wrap btn btn-default"> 
              <input type="file" id="file" /> 
              <p class="">上传文件</p> 
             </div> 
            </div> 
        </div>
       </label>
        <div class="loading_pro">
            <h5 id="select" style="display:">请选择视频文件(*.mp4,*.flv),图片(*.png, *.jpg, *.gif)</h5>              
            <h5 id="uping" style="display:none">上传中<span class="dotting" style="display: "></span></h5> 
            <h5 id="upend" style="display:none">上传成功</h5>
            
            
            <div class="row" id="process1" style="display: none"> 
                <div class="col-md-4">
                校验文件进度
                </div> 
                <div class="col-md-8"> 
                    <div class="progress"> 
                        <div id="checkProcessStyle" class="progress-bar" style="width:0%"></div> 
                        <p id="checkProcessValue" class="value">0%</p> 
                    </div> 
                </div> 
            </div> 
            <div class="row" id="process2" style="display: none"> 
            <div class="col-md-4">
            上传文件进度
            </div> 
            <div class="col-md-8"> 
            <div class="progress"> 
            <div id="uploadProcessStyle" class="progress-bar" style="width:0%"></div> 
            <p id="uploadProcessValue" class="value">0%</p> 
            </div> 
            </div> 
            </div>
        </div> 
                <div class="close_btn">
                    返回
                </div>
      </div> 
      <script src="./lib/jquery-1.10.2.min.js"></script> 
      <script src="./bootstrap/bootstrap.min.js"></script> 
      <script src="./lib/spark-md5.min.js"></script> 
      <script>
            let baseUrl = 'http://[这里写服务器ip]'
            let chunkSize = 5 * 1024  * 1024            
            let fileSize = 0
            let file = null
            let hasUploaded = 0
            let chunks = 0
            // spark = new SparkMD5.ArrayBuffer()
            $("#file").on('change', function () {       
                file = this.files[0]
                fileSize = file.size;
                responseChange(file)
            })
    
            // 0.响应点击
            async function responseChange(file) {
                
    
                document.getElementById("select").style.display="none";
                document.getElementById("uping").style.display="";
                
                
                //document.getElementById("sp").style.display="none";
                // 第一步:按照 修改时间+文件名称+最后修改时间-->MD5
                // 显示文件校验进度
                $("#process1").slideDown(200)
                
                //var a = document.getElementById("input-caption").innerText;
               // var a = document.getElementsByClassName("input-caption");
               // $(".input-caption").html() = "bbbbbbb";
              y = document.getElementById("input-caption");
                y.innerHTML = file.name;           
                // 开始校验
                let fileMd5Value = await md5File(file) // 生成
                //alert("fileMd5Value =" + fileMd5Value);
                // 第二步:校验文件的MD5
                let result = await checkFileMD5(file.name, fileMd5Value);       
                    
                var RESULT = eval(result);                           
                // 如果文件已存在, 就秒传
                if (RESULT.filename) {
                    //alert('文件已秒传');
                    document.getElementById("process1").style.display="none";
                    document.getElementById("process2").style.display="none";  
                            
                    var y = document.getElementById("upend");
                    y.innerHTML = "上传已完成";
                    document.getElementById("select").style.display="none";
                    document.getElementById("uping").style.display="none";
                    document.getElementById("upend").style.display="";
                    
                    return;
                }
                 let exit = false
                // alert("result.chunkList = " + result.chunkList); 
                 
                    
                // 显示文件上传进度
                $("#process2").slideDown(200)
            
                
            
                // 第三步:检查并上传MD5
               // alert("result.chunkList = " + result.chunkList);           
                 // 第三步:检查并上传MD5          
               await checkAndUploadChunk(fileMd5Value, RESULT.chunkList, file);
               
              
               await notifyServer(fileMd5Value, file, chunks);  
    
                //alert("hasUploaded" + hasUploaded); // Compute hash
                // 第四步: 通知服务器所有分片已上传完成
               // notifyServer(fileMd5Value)
            }
    
            // 1.修改时间+文件名称+最后修改时间-->MD5
            function md5File(file) {
                return new Promise((resolve, reject) => {
                    var blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice,
                        //chunkSize = 2097152, // Read in chunks of 2MB
                        chunkSize = file.size / 100,
                        //chunks = Math.ceil(file.size / chunkSize),
                        chunks = 100,
                        currentChunk = 0,
                        spark = new SparkMD5.ArrayBuffer(),
                        fileReader = new FileReader();
    
                    fileReader.onload = function (e) {
                        //console.log('read chunk nr', currentChunk + 1, 'of', chunks);
                        spark.append(e.target.result); // Append array buffer
                        currentChunk++;
    
                        if (currentChunk < chunks) {
                            loadNext();
                        } else {
                            let cur = +(new Date())
                            //console.log('finished loading');
                            // alert(spark.end() + '---' + (cur - pre)); // Compute hash
                            let result = spark.end()
                            resolve(result)
                        }
                    };
    
                    fileReader.onerror = function () {
                        //console.warn('oops, something went wrong.');
                    };
    
                    function loadNext() {
                        var start = currentChunk * chunkSize,
                            end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
    
                        fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
                        $("#checkProcessStyle").css({
                            width: (currentChunk + 1) + '%'
                        })
                        $("#checkProcessValue").html((currentChunk + 1) + '%')
                        // $("#tip").html(currentChunk)
                    }
                    loadNext();
                })
            }
            
            //2.校验文件的MD5
            function checkFileMD5(fileName, fileMd5Value) {
                return new Promise((resolve, reject) => {
                    //let url = baseUrl + '/check/file?fileName=' + fileName + "&fileMd5Value=" + fileMd5Value
                    /*
                        检查文件是否存在,如果整个文件以存在或不存在返回文件名,如果是存在文件块返回文件块列表(json格式),
                        filename            上传文件名
                        fileMd5Value        上传文件MD5值
                        method              要调用的方法名
                    
                    */
                    let url = baseUrl + '/upload.cgi?filename=' + fileName + "&fileMd5Value=" + fileMd5Value + "&method=" + "check";
                    $.getJSON(url, function (data) {
                        resolve(data)   
                    })              
                })          
            }
            
            
            // 3.上传chunk
            async function checkAndUploadChunk(fileMd5Value, chunkList, file) {         
                chunks = Math.ceil(fileSize / chunkSize)    //片段数等于文件总大小除去一个片段的大小   
                        
                //let exit = false;
                var List =  eval(chunkList);
        
                var hasUploaded = 0;
                var len = 0;
                if((chunkList != null) && (chunkList != "") && (chunkList != undefined))
                {
                    hasUploaded = List.length   
                    len = List.length;
                }
                
                        
                /*获取json文件列表,判断文件列表中的 文件*/           
               //console.log("chunks: "+ chunks + " List: "+ List.length + " hasUploaded = " + hasUploaded);
         
                for (var i = 0; i < chunks; i++) 
                {                           
                    //let exit = chunkList.indexOf(i + "") > -1 
                        
                    let exit  = false;
                    if(i < len)
                    {                   
                        if((chunkList != null) && (chunkList != "") && (chunkList != undefined) && (chunkList[i].filename != null) && (chunkList[i].filename != undefined) && (chunkList[i].filename != "") )
                        {                                       
                            for(var j =0; j < len; j++)
                            {
                                if(chunkList[j].filename.indexOf(i + '') > -1)
                                {
                                    exit = true;                                
                                }                           
                            }                                                                                           
                        }                   
                    }
                      
                                                                                     
                  // 如果已经存在, 则不用再上传当前块
                   if (!exit)  
                   {                                                
                       let index = await upload(i, fileMd5Value, chunks, file);
                        hasUploaded++;
                                                                
                        let radio = Math.floor((hasUploaded / chunks) * 100);
                        $("#uploadProcessStyle").css({
                            width: radio + '%'
                        })
                        $("#uploadProcessValue").html(radio + '%');
                    }
                }
            }
    
            // 3-2. 上传chunk
            function upload(i, fileMd5Value, chunks, file) {
                return new Promise((resolve, reject) => {
                    //构造一个表单,FormData是HTML5新增的
                    let end = (i + 1) * chunkSize >= file.size ? file.size : (i + 1) * chunkSize
                    let form = new FormData()
                    form.append("data", file.slice(i * chunkSize, end)) //file对象的slice方法用于切出文件的一部分
                    form.append("total", chunks) //总片数
                    form.append("index", i) //当前是第几片     
                    form.append("fileMd5Value", fileMd5Value)
                    /*
                        传输文件块
                        method   请求方法名
                    
                    */
                    
                    
                    $.ajax({
                        url: baseUrl + '/upload.cgi?method=' + "upload" + "&filename=" + file.name + "&fileMd5Value=" + fileMd5Value, 
                        
                        type: "POST",
                        data: form, //刚刚构建的form数据对象
                        async: true, //异步
                        processData: false, //很重要,告诉jquery不要对form进行处理
                        contentType: false, //很重要,指定为false才能形成正确的Content-Type
                        success: function (data) {
                            resolve(data.desc)
                        }
                    })              
                })
            }
    
            // 第四步: 通知服务器所有分片已上传完成
            function notifyServer(fileMd5Value, file , chunks) {
                document.getElementById("process1").style.display="none";
                document.getElementById("process2").style.display="none";
                //document.getElementById("sp").style.display="none";
                //var y = document.getElementById("uping");
                //y.innerHTML = "上传成功";
                
                document.getElementById("select").style.display="none";
                document.getElementById("uping").style.display="none";
                document.getElementById("upend").style.display="";
                
                
                /*
                    发送合并请求
                    fileMd5Value      文件的MD5值
                    fileName          文件名
                    size              文件大小
                    method            请求的方法名
                */
                
                let url = baseUrl + '/upload.cgi?fileMd5Value=' + fileMd5Value + "&filename=" + file.name + "&size=" + file.size  + "&method=" + "merge" + "&chunks=" + chunks;
                $.getJSON(url, function (data) {                
                    //alert('上传成功')
                })
            }
    
            function getDate() {
                let d = new Date()
                return d.getMinutes() + ':' + d.getSeconds() + ' ' + d.getMilliseconds()
            }
        </script>  
     </body>
    </html>
    

    相关文章

      网友评论

          本文标题:改写文件上传支持断点续传-前端JS代码

          本文链接:https://www.haomeiwen.com/subject/vqcqtftx.html