本文主要通过原生的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 =
' '
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 =
'' +
'' +
fileName + '';
} else {
newli.innerHTML =
'' +
'' +
fileName + '';
}
} else {
if (id) {
newli.innerHTML =
'' +
'' +
fileName + '';
} else {
newli.innerHTML =
'' +
'' +
fileName + '';
}
}
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 关键代码
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
3.4 参考样式
app.css
.btn-upload{
opacity: 0;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: 10;
}