H5移動端原生JS封裝附件上傳服務器

本文主要通過原生的js封裝附件上傳upload.js。可成功內嵌釘釘,ios和安卓端可正常使用,支持單個、多個附件上傳。

一、業務需求

封裝原生JS附件上傳,動態創建附件列表,可對附件列表進行刪除和新增功能。

二、業務邏輯

2.1 app.js 全局封裝ajax請求,附件上傳將文件流傳遞給後端,便於接收。

注:如果傳遞base64位字符串,字節長度解析可能導致服務器的端口過載或者文件太大拋異常。

2.2 原生js封裝upload.js,適用於只讀和非只讀的兩種情況下,後者可上傳附件和編輯附件,前者只能查看和下載操作,對於新上傳的附件,暫不支持預覽等下載操作。單個附件控制不大於50M。

對於新上傳的附件,暫不支持預覽等下載操作說明:由於原生window.open直接打開base64位,會有默認的防釣魚操作,實現上有安全性考慮。可通過上傳服務器再返回,實現該附件下載或預覽的統一操作,但會佔用服務器資源,此處暫不支持。

2.3 代碼的引入和調用
儘量可能做到js調用只用一行代碼實現,增加便捷和可行性。

2.4 全局的基礎樣式美化
現在點擊位置寫好按鈕的樣式,圖片效果最佳。通過將input type = file 設置絕對定位,寬高100%,上左定位爲0,透明度爲0,層級z-index在點擊位置之上即可。建議層級比圖片高一級即可。

三、實例代碼

3.1 app.js

ajaxFile: function(option) {  // 通過formData的形式將附件的文件流請求發給後端
		ajaxCount++;
		var _ajaxCount = ajaxCount; 
		if (!option.error) {
			option.error = ajaxError;  
		}
		return $.ajax({
			type: option.type || "POST",
			url: app.getItem(app.localKey.url) + option.url,  // 自行配置URL
			timeout: option.timeout || 5 * 60 * 1000,
			dataType: "json",
			data: option.data,
			processData: false, // ajax不處理髮送的數據
			contentType : false,
			success: function(r) {  // 返回值根據實際情況再做調整
				if (option.mustexe && option.validateUserInfo) {
					option.success && option.success(r);
				} else if (_ajaxCount == ajaxCount && option.validateUserInfo) {
					option.success && option.success(r);
				}
			},
			error: option.error
		});
	},
	attach: function(fileId, url) { // 附件下載
	var isDD = app.getItem(app.localKey.isDD) || app.otherLogin;  // 用戶信息,下載校驗
		var _url = app.serverUrl + "file.sp?act=fileDownload&loginUser=" + app.getItem(app.localKey.loginUser) +
			"&encAttachId=" + fileId + "&isDD=" + isDD;
		if (url) {
			_url = url;
		}
		window.open(_url);
	},

3.2 upload.js
以下方法調用了mui.js做彈窗提示組件,如需引入jq可以自行修改。

(function(doc, $, app) {
	window.upload = {
		isRead: false, // 默認false,附件是否只讀,否可以上傳附件,否可以刪除附件
		uploadFiles: [], // 新附件
		oldFiles: [], // 舊附件
		onReady: function(isRead, obj) { // 附件列表初始化isRead 是否只讀 obj爲舊附件的對象
			upload.isRead = isRead;
			if(obj&& obj.length>0){ // 是否有數據傳遞
				upload.oldFiles = obj; // 新舊數組的操作
				upload._isShowFileTitle();
				for (var i = 0, e; i < obj.length; i++) {
					e = obj[i];
					upload._innerHTML(e.name, e.id);
				}
			}
			var uploadBtn = $("#uploadBtn")[0]; // 附件上傳按鈕
			if (upload.isRead) {
				if (uploadBtn) {
					uploadBtn.innerHTML = "";
				}
			} else {
				if (uploadBtn) {
					var newtd =
						'<td width="100px" align="left" valign="middle"><div class="grid"><label class="title">附件</label></div></td><td width="*" align="left" valign="middle"><input class="btn-upload" type="file" accept="*" name="upload" id="uploadfile" multiple /><a class="mui-btn mui-icon mui-icon-upload"  style="margin: 10px;"></a></td><td width="40px"><div class="grid"><a class="mui-navigate-right"></a></div></td>'
					uploadBtn.innerHTML = newtd;
				}
				var input = $("#uploadfile")[0];
				input.onchange = function() {
					readFile(this);
				}
				var readFile = function(obj) {
					for (var i = 0; i < obj.files.length; i++) {
						var path = obj.files[i],
							fileName = path.name;
						if (path.size < 1024 * 1024 * 50) {
							upload.uploadFiles.push(path);
							upload._innerHTML(path.name);
						} else {
							$.toast('單個附件大小不能超過50M');
						}
						
					}
					input.value = "";
					upload._isShowFileTitle();
				}
			}
		},
		_innerHTML(fileName, id) {  // 附件列表動態輸出
			var ul = ul = $('#selectList')[0];
			var newli = doc.createElement('li');
			var img = upload._getIcon(fileName);
			newli.setAttribute("class", "mui-table-view-cell text-overflow");
			newli.setAttribute("style", "height:44px;");

			if (upload.isRead) { // 只讀沒有刪除按鈕
				if (id) {
					newli.innerHTML =
						'<div class="mui-pull-left"><img src="../../images/download/' + img +
						'" style="height:32px;padding-bottom:10px;"></img></div>' +
						'<div class="mui-media-body"><div onclick="app.attach(\'' + id + '\');" class="mui-ellipsis">' +
						fileName + '</div></div>';
				} else {
					newli.innerHTML =
						'<div class="mui-pull-left"><img src="../../images/download/' + img +
						'" style="height:32px;padding-bottom:10px;"></img></div>' +
						'<div class="mui-media-body"><div class="mui-ellipsis">' +
						fileName + '</div></div>';
				}
			} else {
				if (id) {
					newli.innerHTML =
						'<div class="mui-pull-left"><img src="../../images/download/' + img +
						'" style="height:32px;padding-bottom:10px;"></img></div><div class="mui-pull-right" onclick="upload._delElement(this,\'' +
						fileName + '\')"><img src="../../images/task/delete.png" style="height:24px;"></img></div>' +
						'<div class="mui-media-body"><div onclick="app.attach(\'' + id + '\');" class="mui-ellipsis">' +
						fileName + '</div></div>';
				} else {
					newli.innerHTML =
						'<div class="mui-pull-left"><img src="../../images/download/' + img +
						'" style="height:32px;padding-bottom:10px;"></img></div><div class="mui-pull-right" onclick="upload._delElement(this,\'' +
						fileName + '\')"><img src="../../images/task/delete.png" style="height:24px;"></img></div>' +
						'<div class="mui-media-body"><div class="mui-ellipsis">' +
						fileName + '</div></div>';
				}
			}
			newli.setAttribute('fileName', fileName);
			ul.appendChild(newli);
		},
		_getIcon(name) { // 附件圖標 如果沒有一一匹配的圖表,請默認一個圖片
			var type = name.substr(name.lastIndexOf('.') + 1).toLowerCase(); //判斷文件類型
			var img = "";
			if ('png' != type && 'doc' != type && 'jpg' != type && 'pdf' != type && 'rar' != type && 'txt' != type && 'wav' !=
				type && 'xls' != type && 'zip' != type) {
				img = 'file-file.png';
			} else {
				img = 'file-' + type + '.png';
			}
			return img;
		},
		_delElement(obj, filename) { // 刪除附件
			$.confirm('是否要刪除該附件?', '*****', ['確定', '取消'], function(e) {
				if (e.index == 0) {
					var ul = obj.parentNode.parentNode;
					ul.removeChild(obj.parentNode); // 刪除節點
					for (var i = 0; i < upload.uploadFiles.length; i++) {
						var e = upload.uploadFiles[i];
						if (e.name == filename) {
							upload.uploadFiles.splice(i, 1);
							upload._isShowFileTitle(); // 判斷是否顯示附件列表
							$.toast('刪除成功');
							return;
						}
					}
					if (upload.oldFiles) {
						for (var i = 0; i < upload.oldFiles.length; i++) {
							var e = upload.oldFiles[i];
							if (e.name == filename) {
								upload.oldFiles.splice(i, 1);
								upload._isShowFileTitle(); // 判斷是否顯示附件列表
								// taskFeedbkEdit.updataFile(); // 獲取就舊數組傳值
								$.toast('刪除成功');
								return;
							}
						}
					}

				}
			});
		},
		_isShowFileTitle() { // 添加頁是否顯示附加標題 && 編輯頁判斷數組是否爲空
			var appendix = $("#appendix")[0];
			if (appendix) {
				if (upload.uploadFiles.length > 0 || upload.oldFiles.length > 0) {
					appendix.style.display = "block";
				} else {
					appendix.style.display = "none";
				}
			} else {
				var empty = doc.getElementById("empty");
				if (upload.oldFiles.length == 0 && upload.uploadFiles.length == 0 && upload.isRead) {
					var ul = doc.getElementById("selectList");
					ul.innerHTML = "";
					var m = doc.createElement("li");
					m.id = "empty";
					m.setAttribute("class", "mui-table-view");
					m.setAttribute("style", "background-color: #FFF;padding: 10px;margin-top: 0;");
					m.innerHTML = "暫無附件。";
					ul.appendChild(m);
				} 
			}

		},
		_getFormData(paramObj) { // 帶附件的ajax請求 將參數轉爲formData的形式
			var formData = new FormData();
			if (paramObj) {
				for (var key in paramObj) {
					if (typeof paramObj[key] == "object" && paramObj[key].length) {
						var data = paramObj[key];
						data.map(e => {
							formData.append(key, e);
						})
					} else {
						formData.append(key, paramObj[key])
					}
				}
			}
			// 用戶標識 默認上傳
			var loginUser = app.getItem(app.localKey.loginUser),
				isDD = app.getItem(app.localKey.isDD) || app.otherLogin;
			var user = JSON.parse(localStorage.getItem("userInfo"));
			if (loginUser) {
				formData.append("loginUser", loginUser);
			}
			if (isDD) {
				formData.append("isDD", isDD);
			}
			return formData;
		},
	}
})(document, mui, app)

3.3 引入和調用
3.3.1 index.html 關鍵代碼

<tr id="uploadBtn"></tr>


<div class="split_bar" id="appendix" style="display: none;">附件列表</div>
<ul id="selectList" class="mui-table-view"></ul>


<script src="../../js/mui.min.js"></script>
<script src="../../js/app.js"></script>
<script src="../../js/upload.js"></script>
<script src="../../js/index.js"></script>

3.3.2 index.js 文件代碼
① upload.js調用,附件初始化

upload.onReady();  //附件初始化,附件刪除

upload.onReady(false, obj); // 附件初始化,不可編輯,舊附件顯示

upload.onReady(true, rfat); // 附件初始化,可編輯,舊附件顯示

② ajax請求調用

var data = {};
for(var i = 0; i<upload.uploadFiles.length;i++){
var filePath = upload.uploadFiles[i];
	console.log(filePath)
	data["filedata" + i] = filePath;
}
var  FormData = upload._getFormData(data);
app.ajaxFile({
	url: "saveTask", // URL自行修改
	data: FormData,
	success: function(r) {
		if (r == '1') {
			$.toast("保存成功"); // mui.js組件
			setTimeout(function() {
				app.go();
			}, 500);
		} else {
			mui.toast(r); // mui.js組件
		}
		app.closeWaiting(); // 全局app.js組件
	}
});

3.4 參考樣式
app.css

.btn-upload{
	opacity: 0;
	position: absolute;
	left: 0;
	top: 0;
	width: 100%;
	height: 100%;
	z-index: 10;
}

四、效果如下

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章