js 文件異步上傳 顯示進度條 顯示上傳速度 預覽文件
通常文件異步提交有幾個關鍵
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 文件異步上傳 顯示進度條 顯示上傳速度 預覽文件