天天看点

阿里云 OSS 上传插件layui-aliossuploader升级为带进度条及单项回调

最近有个项目,要上传无数素材到阿里云,找了很多layui的上传组件,感觉要么复杂化,要么就是没带进度条,layui官方的进度条是带了,但是没有上传到阿里云oss的,而且在折腾成功之前,layui的file还在前面,截止2022年11月8日,layui官方才更新了,把file放到表单域的后面。 但是我是没有多少去折腾官方那种上传oss的。后面找到了这个layui-aliossuploader的第三方组件,一番折腾,感觉蛮好。美中不足的是,没有进度条。

去作者blog查看,作者也说不会… 经历痛苦的搜索之后…思来想去,不就是ajax 嘛,看能否从这入手,加上这个进度条。。。。 debug一下午后,奇迹般搞定了。

然后再回过头来看,我靠,如此简单?真的是自己太菜了!

搁这保存起来警示警示吧。

带进度条的 aliossuploader.js

layui.extend({}).define(['layer', 'upload','element'], function(exports) {
	var $ = layui.$,
		layer = layui.layer,
		upload = layui.upload,
		element=layui.element, //新加
		allUploaded = {},
		policyFailed = null,
		itemUploaded =null,
		uploadData = [],
		prefixPath,
		layerTitle,
		filesss = {},
		successCount = 0,
		uploadCount = 0,
		filesListView = null,
		multiple = false,
		multipleFileArray = [],
		multipleFileKeyArray = [],
		uplaod = layui.upload;
	//加载样式

	var Class = function(options) {
		var that = this;
		that.options = options;
		that.init();
	};

	Class.prototype.init = function() {
		var that = this,
			options = that.options;
		if (options.layerArea) {
			layerArea = options.layerArea;
		} else {
			layerArea = 'auto';
		}
		if (options.multiple) {
			multiple = true;
		}
		if (!that.strIsNull(that.options.fileType)) {
			fileType = that.options.fileType;
		}else{
			fileType = 'file';
		}
		if (!that.strIsNull(that.options.httpStr)) {
			httpStr = that.options.httpStr;
		} else {
			httpStr = 'https';
		}
		if (!that.strIsNull(that.options.policyFiled)) {
			policyFiled = that.options.policyFiled;
		} else {
			policyFiled = 'policy';
		}
		if (!that.strIsNull(that.options.accessidFiled)) {
			accessidFiled = that.options.accessidFiled;
		} else {
			accessidFiled = 'accessid';
		}
		if (!that.strIsNull(that.options.codeFiled)) {
			codeFiled = that.options.codeFiled;
		} else {
			codeFiled = '';
		}
		if (!that.strIsNull(that.options.codeStatus)) {
			codeStatus = that.options.codeStatus;
		} else {
			codeStatus = 0;
		}
		if (!that.strIsNull(that.options.signatureFiled)) {
			signatureFiled = that.options.signatureFiled;
		} else {
			signatureFiled = 'signature';
		}
		if (!that.strIsNull(that.options.region)) {
			region = that.options.region;
		}
		if (!that.strIsNull(that.options.prefixPath)) {
			prefixPath = that.options.prefixPath;
		} else {
			prefixPath = '';
		}
		if (!that.strIsNull(that.options.policyUrl)) {
			policyUrl = that.options.policyUrl;
		}
		if (typeof that.options.policyData != 'undefined') {
			policyData = that.options.policyData;
		} else {
			policyData = {};
		}
		if (typeof that.options.policyHeader != 'undefined') {
			policyHeader = that.options.policyHeader;
		} else {
			policyHeader = {};
		}
		if (typeof that.options.uploadRenderData != 'undefined') {
			uploadRenderData = that.options.uploadRenderData;
		} else {
			uploadRenderData = {};
		}
		if (!that.strIsNull(that.options.policyMethod)) {
			policyMethod = that.options.policyMethod;
		} else {
			policyMethod = 'GET';
		}
		if (!that.strIsNull(that.options.bucket)) {
			bucket = that.options.bucket;
		}
		allUploaded[that.options.elm] = that.options.allUploaded;
		itemUploaded = that.options.itemUploaded;
		policyFailed = that.options.policyFailed;
		if (!that.strIsNull(that.options.layerTitle)) {
			layerTitle = that.options.layerTitle;
		} else {
			layerTitle = '上传文件到阿里云OSS';
		}
		if (multiple) {
			$(that.options.elm).on('click', function() {
				layer.open({
					type: 1,
					area: layerArea, //宽高
					resize: false,
					title: layerTitle,
					content: '<div class="layui-col-md12">' +
						'<div class="layui-card">' +
						'<div class="layui-card-body">' +
						'<div class="layui-upload">' +
						'<button type="button" class="pear-btn pear-btn-primary pear-btn-md" id="test-upload-files">选择文件</button>' +
						'<div class="layui-upload-list">' +
						'<table class="layui-table">' +
						'<thead>' +
						'<tr>' +
						'<th>文件名</th>' +
						'<th>大小</th>' +
						'<th>上传进度</th>' +
						'<th>操作</th>' +
						'</tr>' +
						'</thead>' +
						'<tbody id="test-upload-filesList"></tbody>' +
						'</table>' +
						'</div>' +
						'<button type="button" class="pear-btn pear-btn-danger pear-btn-md" id="test-upload-filesAction">开始上传</button>' +
						'</div>' +
						'</div>' +
						'</div>' +
						'</div>',
					success: function(layero, index) {
							$('#test-upload-filesAction').on('click', function() {
								if(typeof uploadListIns.config.files == 'undefined'){
									layer.msg('请先选择要上传的文件!',{shade:'rgba(0,0,0,0)'});
									return;
								}
								layer.open({type: 3, icon: 1});
								//先获取police信息
								$.ajax({
									url: policyUrl,
									type: policyMethod,
									data: policyData,
									headers: policyHeader,
									success: function(res) {
										
										var successStatus = false;
										if (codeFiled) {
											if (res[codeFiled] == codeStatus) {
												successStatus = true;
											}
										} else {
											successStatus = true;
										}
										if (successStatus) {
											// 签名成功开始上传文件
											var files = uploadListIns.config.files;
											//清空原来返回的数组
											uploadData = [];
											var fileCount = 0;
											for (var filekey in files) {
												fileCount++;
											}
											res.data.signature = res.data[signatureFiled];
											res.data.accessid = res.data[accessidFiled];
											res.data.policy = res.data[policyFiled];
											for (var filekey in files) {
												var tr = filesListView.find('tr#upload-' + filekey),
													tds = tr.children();
												
												if (tds.eq(2).text() == '') {
													that.uploadFile(files, filekey, fileCount, res.data);
												} else {
													// successCount++;
													fileCount--;
													if(fileCount == 0){
														layer.closeAll('loading');
														layer.msg('没有文件需要上传');
													}
												}
											}
										} else {
											policyFailed(res);
										}

									},
									error: function(res) {
										policyFailed(res);
									}
								});

							})
							filesListView = $('#test-upload-filesList'),
							uploadListIns = upload.render($.extend({
								elem: '#test-upload-files',
								url: httpStr+'://'+bucket + '.' + region + '.aliyuncs.com',
								accept: fileType,
								multiple: true,
								auto: false,
								choose: function(obj) {
									var files = this.files = obj.pushFile(); //将每次选择的文件追加到文件队列
									//读取本地文件
									obj.preview(function(index, file, result) {
										var tr = $(['<tr id="upload-' + index + '">', '<td>' + file.name + '</td>', '<td>' + (file.size /
												1014).toFixed(
												1) + 'kb</td>',
											'<td><div class="layui-progress" lay-showpercent="true"  lay-filter="progress-demo-'+ index +'"><div class="layui-progress-bar" lay-percent=""></div></div></td>',
											'<td>',
											'<button class="pear-btn pear-btn-mini test-upload-demo-reload layui-hide">重传</button>',
											'<button class="pear-btn pear-btn-mini pear-btn-danger test-upload-demo-delete">删除</button>',
											'</td>',
											'</tr>'
										].join(''));

										//删除
										tr.find('.test-upload-demo-delete').on('click', function() {
											delete files[index]; //删除对应的文件
											tr.remove();
											uploadListIns.config.elem.next()[0].value = ''; //清空 input file 值,以免删除后出现同名文件不可选
										});
										filesListView.append(tr);
										element.render('progress'); //渲染新加的进度条组件
										
									});
								},
								
							},uploadRenderData));
						} //可以自行添加按钮关闭,关闭请清空rowData
						,

					end: function() {
						if (options.success) {
							if (typeof options.success === 'function') {
								options.success();
							}
						}
					}
				});
			})
		} else {
			upload.render($.extend({
				elem: that.options.elm,
				url: httpStr+'://'+bucket + '.' + region + '.aliyuncs.com',
				accept: fileType,
				multiple: false,
				auto: false,
				choose: function(obj) {
					layer.open({type: 3, icon: 1});
					var files = this.files = obj.pushFile(); //将每次选择的文件追加到文件队列
					if (JSON.stringify(filesss) == '{}') {
						filesss = JSON.parse(JSON.stringify(files));

					} else {
						for (var file in files) {
							if (file in filesss) {
								delete files[file];
							}
						}
						filesss = JSON.parse(JSON.stringify(files));
					}
					//读取本地文件
					successCount = 0;
					//先获取police信息
					$.ajax({
						url: policyUrl,
						type: policyMethod,
						data: policyData,
						headers: policyHeader,
						success: function(res) {
							//console.log(res);
							var successStatus = false;
							if (codeFiled) {
								if (res[codeFiled] == codeStatus) {
									successStatus = true;
								}
							} else {
								successStatus = true;
							}
							if (successStatus) {
								// 签名成功开始上传文件
								res.data.signature = res.data[signatureFiled];
								res.data.accessid = res.data[accessidFiled];
								res.data.policy = res.data[policyFiled];
								for (var filekey in files) {
									that.uploadFile(files, filekey, 1, res.data);
								}
							} else {
								policyFailed(res);
							}

						},
						error: function(res) {
							policyFailed(res);
						}
					});

				}
			},uploadRenderData));
		}
	};



	Class.prototype.strIsNull = function(str) {
		if (typeof str == "undefined" || str == null || str == "")
			return true;
		else
			return false;
	};


	Class.prototype.uploadFile = function(filess, filekey, fileCount, data) {
		var multipleState = this.options.multiple;
		//console.log(filekey);
		multipleFileArray.push(filess[filekey]);
		data.file = filess[filekey];
		var filedata = new FormData();
		multipleFileKeyArray.push(this.options.prefixPath + new Date().getTime() + '-' + (Math.random() + "").substring(2, 7) + '-' + data.file.name);
		filedata.append('key', multipleFileKeyArray[uploadCount]);
		filedata.append('policy', data.policy);
		filedata.append('OSSAccessKeyId', data.accessid);
		filedata.append('signature', data.signature);
		filedata.append('success_action_status', 200);
		filedata.append('file', multipleFileArray[uploadCount]);
		uploadCount++;
		var upfiles = filesss;
		var that = this;
		$.ajax({
			url: httpStr+'://'+ bucket + '.' + region + '.aliyuncs.com',
			processData: false,
			cache: false,
			contentType: false,
			type: 'POST',
			data: filedata,
			xhr:function(){ //上传进度,点晴之笔
				var xhr=new XMLHttpRequest();
				xhr.upload.addEventListener('progress',function(e){
					//console.log(e);
					var progressRate=(e.loaded/e.total)*100;
					progressRate=progressRate.toFixed(2);
					 element.progress('progress-demo-'+ filekey, progressRate + '%');
				})
				return xhr;
			},
			success: function(e) {
				var result = {
					name: multipleFileArray[successCount].name,
					type: multipleFileArray[successCount].type,
					ossUrl: httpStr+'://'+bucket + '.' + region + '.aliyuncs.com' + '/' + multipleFileKeyArray[successCount]
				};
				//成功无返回
				if (multipleState) {
					uploadData.push(result);
					var tr = filesListView.find('tr#upload-' + filekey),
						tds = tr.children();
					tds.eq(2).html('<span style="color: #5FB878;">上传成功</span>');
					tds.eq(3).html(''); //清空操作
				} else {
					uploadData = [result];
					delete upfiles[0];
				}
				if(result){
					itemUploaded(result); //单上文件上传的回调
				}
				successCount++;
				if (successCount == fileCount) {
					successCount = 0;
					fileCount = 0;
					uploadCount = 0;
					multipleFileArray = [];
					multipleFileKeyArray = [];
					layer.closeAll('loading');
					allUploaded[that.options.elm](uploadData);
				}
			},
			error: function(i) {
				console.log(i)
			}
		})
	};

	Class.prototype.removeArray = function(array, fileId) {
		for (var i = 0; i < array.length; i++) {
			if (array[i].fileId == fileId) {
				array.splice(i, 1);
			}
		}
		return array;
	};

	var aliossUploader = {
		render: function(options) {
			var inst = new Class(options);
			return inst;
		}

	};

	exports('aliossUploader', aliossUploader);
});

           

为了自己方便,还塞了一个单项上传完成之后的回调函数itemUploaded

前端的使用和调用,跟第三方组件完全一样

原来的aliossuploader 组件地址在这里

https://blog.coder666.cn/2019/04/10/blog27/

有需要的,去上面拿吧。

改动的地方主要就在

uploadfile 函数部分,增加了一个 xhr 监控

xhr:function(){ //上传进度
				var xhr=new XMLHttpRequest();
				xhr.upload.addEventListener('progress',function(e){
					//console.log(e);
					var progressRate=(e.loaded/e.total)*100;
					progressRate=progressRate.toFixed(2);
					 element.progress('progress-demo-'+ filekey, progressRate + '%');
				})
				return xhr;
			},
           

其他没有啥了。看源码就可以了。 或者直接复制过去。

继续阅读