1. 程式人生 > >js 文件異步上傳 顯示進度條 顯示上傳速度 預覽文件

js 文件異步上傳 顯示進度條 顯示上傳速度 預覽文件

response null acc 文件的 pen 實現 accept https 提交

通常文件異步提交有幾個關鍵

1.支持拖拽放入文件。2.限制文件格式。3.預覽圖片文件。4.上傳進度,速度等,上傳途中取消上傳。5.數據與文件同時上傳

現在開始筆記:

需要一個最基礎的元素<input id="inputFile" type=file multiple="multiple">

一、首先我們需要實現最基本的異步上傳功能

//獲得input元素的文件

var fileObj = document.getElementById("inputFile").files;

//定義一個表單數據對象

var form = new formData();

//將文件input的文件信息放入表單數據對象中

for(var i in fileObj)
{
form.append("file[]", fileObj[i]); // 文件對象
}

//定義一個xhr對象

var xhr = new XMLHttpRequest() || new ActiveXObject("Microsoft.XMLHTTP");

//創建一個http請求

xhr.open("post",url,true);

//發送數據

xhr.send(form);

這樣數據就上傳成功了。

二、接下來說明如何捕獲文件上傳開始,過程中,結束的各種信息狀態

主要是幾個xhr回調函數

xhr.onload = function(evt){};//上傳請求完成

xhr.onerror = function(evt){};//上傳異常

xhr.upload.onloadstart = function(evt){};//開始上傳

xhr.upload.onprogress =function(evt){};//上傳進度 這個方法會在文件每上傳一定字節時調用

evt.loaded//表示已經上傳了多少byte的文件大小

evt.total//表示文件總大小為多少byte

通過這兩個關鍵的屬性就可以去計算 上傳進度與速度

xhr.onreadystatechange = function(){}//當xhr的狀態(上傳開始,結束,失敗)變化時會調用

該方法可以用來在文件上傳完成後接收服務器返回的內容 xhr.responceText

中途取消上傳 xhr.abort();

三、關於限制文件格式

在fileObj[i]中有個type屬性可以使用

四、傳文件的時候需要傳其他數據

只需要

form.append("name","potatog");

這種鍵值錄入即可。

只是需要註意後臺獲取數據是 不是在$_FILE中。

五、文件拖放

定義一個用來接收拖放事件的元素

如:

<div id="holder" style="width:150px;height:150px;border:5px solid red;"></div>

//檢查瀏覽器是否支持拖放上傳。
  if(‘draggable‘ in document.createElement(‘span‘)){
    var holder = document.getElementById(‘holder‘);
    //當拖放的文件懸浮在該元素上方是觸發
    holder.ondragover = function () { this.className = ‘hover‘; return false; };
    //當拖放的文件不再懸浮在該文件上方時調用
    holder.ondragend = function () { this.className = ‘‘; return false; };
    //當拖放的文件放到該元素中時
    holder.ondrop = function (event) {

      event.preventDefault();

      this.className = ‘‘;

      //得到拖放的文件  
      var files = event.dataTransfer.files;

     //將文件放入輸入框對象的files中
     fileObj.files = files;
     fileObj.onchange();
      return false;
    };

  }

六、預覽圖片

fileObj.onchange = function(){
  // 檢查是否支持FileReader對象
  if (typeof FileReader != ‘undefined‘) {

//能預覽的文件
    var acceptedTypes = {
      ‘image/png‘: true,
      ‘image/jpeg‘: true,
      ‘image/gif‘: true
    };
得到input=file元素中的所有文件信息
for(var i = 0; i < fileObj.files.length; i++)
{

//如果是支持預覽的圖片文件
    if (acceptedTypes[fileObj.files[i].type] === true) {
//新建一個預覽對象
      var reader = new FileReader();
//綁定事件 當數據加載後執行 每有一張圖片載入完成就會別調用。
      reader.onload = function (event) {
//定義一個圖片對象
        var image = new Image();
//將對象載入的結果返回到圖片元用來顯示
        image.src = event.target.result;

        image.width = 100;

        holder.appendChild(image);

      };


//開始加載數據 文件
    reader.readAsDataURL(fileObj.files[i]);
}


    }

  }
}

關於異步上傳的封裝demo代碼

/* pUploadFile.js
 * 使用方法
 * 定義文件異步上傳對象
 * var uploadFile = pUploadFile({
            "elId" : "file",
            "previewId" : "show"
        });
 * 定義時必須傳遞input[type=file]元素的id,
 * preview為選填項  用來預覽圖片文件的div,即圖片文件會以img元素的形式放入preview中
 * 開始上傳
 * 
 * uploadFile.upload({
 *     
 * });
 * 
 * 
 * 定義或者執行上傳是必須其中一著需要傳遞參數
 * url 請求地址
 * callback 回調函數名
 * 
 */

(function(){
    window.pUploadFile = function(config)
    {
        return new PotatogUploadFile(config);
    }
    
    function PotatogUploadFile(config)
    {
        //文件input元素id
        this.elId = null;
        //input元素對象
        this.elObj = null;
        
        this.progressBoxWidth = 0;
        
        //請求地址
        this.url = null;
        //上傳成功後的回調
        this.success = null;
        //上傳失敗後的回調
        this.faild = null;
        
        //遮罩盒子
        this.progressBox = null;
        
        //百分比
        this.percent = 0;
        
        this.progressStreak = null;
        
        this.xhr = new XMLHttpRequest() || new ActiveXObject("Microsoft.XMLHTTP");
        
        this.startTime = 0;
        
        this.preTime = 0;
        
        this.preLoad = 0;
        
        this.count = 10;
        
        this.previewId = null;
        this.previewObj = null;
        
        this.data = null;
        
        if(typeof config["previewId"] != "undefined")
        {
            this.previewId = config["previewId"];
            this.previewObj = document.querySelector("#previewId");
        }
        
        if(typeof config["elId"] == "undefined")
        {
            console.error("元素ID缺失");
            return this;
        }
        else
        {
            this.elId = config["elId"];
            this.elObj = document.querySelector("#file");
            this.inintDom();
        }
        
        this.url = (typeof config.url == "undefined") ? null : config.url;
        this.callback = (typeof config.callback == "undefined") ? null : config.callback;
        this.method = (typeof config.method == "undefined") ? "post" : config.method;
        this.async = (typeof config.async == "undefined") ? true : config.async;
        
    }
    
    //初始化一些交互元素
    PotatogUploadFile.prototype.inintDom = function(){
        var _this = this;
        var inputWidth = this.progressBoxWidth = parseFloat(getComputedStyle(this.elObj).getPropertyValue("width"));
        var inputHeight = parseFloat(getComputedStyle(this.elObj).getPropertyValue("height"));
        
        var inputX = this.elObj.offsetLeft;
        var inputY = this.elObj.offsetTop;
        
        //創建一個元素 用來覆蓋住input元素
        var progressBox = document.createElement("div");
        progressBox.style.display = "none";
        progressBox.style.position = "absolute";
        progressBox.style.zIndex = "999";
        progressBox.style.left = inputX + "px";
        progressBox.style.top = inputY + "px";
        
        progressBox.style.width = inputWidth + "px";
        progressBox.style.height = inputHeight + "px";
        
        progressBox.style.background = "rgba(58,147,255,0.1)";
        progressBox.style.border = "1px solid rgba(58,147,255,0.3)";
        
        this.progressBox = progressBox;
        document.body.appendChild(progressBox);
        
        //進度條
        var progressStreak = document.createElement("div");
        progressStreak.style.height = this.progressBox.style.height;
        
        progressStreak.style.background = "rgba(58,147,255,0.2)";
        
        this.progressStreak = progressStreak;
        this.progressBox.appendChild(progressStreak);
        
        //進度條中間的 百分比文字
        var label = document.createElement("label");
        
        label.style.position = "absolute";
        label.style.top = "0px";
        label.style.right = "5px";
        label.style.lineHeight = this.progressBox.style.height;
        label.style.color = "#3B97FF";
        label.style.fontSize = "10px";
        
        this.label = label;
        this.progressBox.appendChild(label);
        
        //右上角的上傳速度 剩余時間預計
        var speed = document.createElement("span");
        
        
        speed.style.position = "absolute";
        speed.style.right = "0px";
        speed.style.top = "-12px";
        
        
        speed.style.color = "rgba(58,147,255,0.6)";
        speed.style.fontSize = "10px";
        
        this.speed = speed;
        this.progressBox.appendChild(speed);
        
        var predict = document.createElement("span");
        predict.style.position = "absolute";
        predict.style.left = "0px";
        predict.style.top = "-12px";
        
        predict.style.color = "rgba(58,147,255,0.6)";
        predict.style.fontSize = "10px";
        
        this.predict = predict;
        this.progressBox.appendChild(predict);
        
        
        //取消上傳按鈕
        var cancel = document.createElement("span");
        cancel.innerHTML = "×";
        cancel.style.position = "absolute";
        
        cancel.style.top = "-5px";
        cancel.style.right = "1px";
        
        cancel.style.color = "#999";
        cancel.style.cursor = "pointer";
        cancel.onclick = function(){
            _this.progressBox.style.display = "none";
            _this.xhr.abort();
        }
        
        this.cancel = cancel;
        this.progressBox.appendChild(cancel);
    }
    
    
    PotatogUploadFile.prototype.setProgressValue = function(percent)
    {
        this.percent = percent;
        this.progressStreak.style.width = Math.ceil(this.progressBoxWidth * percent) + "px";
        this.label.innerHTML = Math.round(this.percent * 100) + "%";
    }
    
    PotatogUploadFile.prototype.setSpeed = function(value)
    {
        if(value > 1000)value = Math.round(value / 1000 / 1024) +  "M/s";
        else value = value + "K/s"
        this.speed.innerHTML = value;
    }
    
    PotatogUploadFile.prototype.setPredict = function(value)
    {
        var m = parseInt(value / 60);
        var s = value % 60;
        this.predict.innerHTML = "預計剩余:" + m + "分 " + s + "秒";
    }
    
    PotatogUploadFile.prototype.upload = function(config)
    {
        if(this.elObj.value == ‘‘)return false;
        this.url = (typeof config.url == "undefined") ? null : config.url;
        this.callback = (typeof config.callback == "undefined") ? null : config.callback;
        this.method = (typeof config.method == "undefined") ? "post" : config.method;
        this.async = (typeof config.async == "undefined") ? true : config.async;
        this.data = (typeof config.data == "undefined") ? null : config.data;
        
        this.progressBox.style.display = "block";
        this.initXHR();

    }
    
    PotatogUploadFile.prototype.initXHR = function()
    {
        var _this = this;
        this.xhr.open(this.method,this.url,this.async);
        var form = new FormData();
        var files = this.elObj.files;
        if(files.length == 0)
        {
            console.error("未選擇文件");
        }
        
        for(var i in files)
        {
            form.append("file",files[i]);
        }
        
        if(_this.data != null)
        {
            for(var key in _this.data)
            {
                form.append("data[" + key + "]",_this.data[key]);
            }
        }
        
        //上傳開始
        this.xhr.upload.onloadstart = function()
        {
            _this.startTime = (new Date()).getTime();
            _this.preTime = (new Date()).getTime();
            _this.preLoad = 0;
        };
        
        //上傳完成
        this.xhr.onload = function()
        {
            _this.callback(_this.xhr.responseText);
            _this.progressBox.style.display = "none";
        }
        
        //上傳失敗
        this.xhr.onerror =  function()
        {
            console.log("error");
            _this.progressBox.style.display = "none";
            
        }

        //上傳進度
        this.xhr.upload.onprogress = function(evt)
        {

            _this.setProgressValue(evt.loaded / evt.total);
            
            var nowTime = (new Date()).getTime();
            var nowLoad = evt.loaded;

            var timeDelay = (nowTime - _this.preTime) / 1000;
            
            var loadedDelay = nowLoad - _this.preLoad;
            //b/s
            var speed = parseInt(loadedDelay / timeDelay);
            var preTime = Math.round((evt.total - evt.loaded) / speed);
            
            
            _this.count += 1;
            if(_this.count > 10)
            {
                _this.count = 0;
                _this.setSpeed(speed);
                _this.setPredict(preTime);
            }
            _this.preTime = nowTime;
            _this.preLoad = nowLoad;
        }
        this.xhr.send(form);
    }
})(window);

本文參考:

https://www.cnblogs.com/yuanlong1012/p/5127497.html

http://www.ruanyifeng.com/blog/2012/08/file_upload.html

js 文件異步上傳 顯示進度條 顯示上傳速度 預覽文件