改自 @水木易安 的图文快贴插件,原帖:https://hu60.cn/q.php/bbs.topic.97322.html
通过虎绿林附件前端表单直传API实现了直接向阿里云OSS上传文件,避免经过虎绿林web服务器中转,大大提高了上传速度。
而且如果你多次上传同一个文件,还可以实现“秒传”,第二次不需要重新上传即可获得下载链接。
此外,该插件也是用虎绿林附件前端表单直传API进行文件上传的参考实现。
把以下代码导入到网页插件即可:
导入网页插件:图文快贴(当前用户:17,总安装次数:22)<script src="/tpl/classic/js/SparkMD5/spark-md5.min.js"></script>
<script src="/tpl/classic/js/humanize/humanize.js"></script>
<script src="api.webplug-file.1_public_quick_paste_oss.js"></script>
然后就能用这个🚀图文快贴
按钮上传附件了。
<script src="/tpl/classic/js/SparkMD5/spark-md5.min.js"></script>
<script src="/tpl/classic/js/humanize/humanize.js"></script>
<script>
/**图文拖拽快传插件开始**/
$(function () { // 【😭😭😭】
// 粘贴
document.addEventListener('paste', function (event) {
var clipboardData = (event.clipboardData || event.originalEvent.clipboardData);
var files = [];
for (var i=0; i<clipboardData.items.length; i++) {
var file = clipboardData.items[i];
if (file.kind === 'file') {
var file = file.getAsFile();
if (file) {
files.push(file);
}
}
}
if (files.length > 0) {
resolveFileList(files);
}
});
// 拖放
var content = document.getElementById('content');
if(!content) return '😥非帖子页面不继续执行';
content.ondragover = function (ev) {
ev.preventDefault();
this.style.backgroundColor = '#ddd';
}
content.ondragleave = function () {
this.style.backgroundColor = 'inherit';
}
content.ondrop = function (ev) {
this.style.backgroundColor = 'inherit';
ev.preventDefault();
resolveFileList(ev.dataTransfer.files);
}
// 添加按钮
var fastUpBtn = document.createElement('input');
fastUpBtn.id = 'fastUpBtn';
fastUpBtn.style.display = 'none';
fastUpBtn.type = 'file';
fastUpBtn.onchange = function (e) {
resolveFileList(e.target.files);
}
var triggerUpBtn = document.createElement('input');
triggerUpBtn.style.marginLeft = '4px';
triggerUpBtn.type = 'button';
triggerUpBtn.value = '🚀图文快贴';
triggerUpBtn.onclick = function () {
fastUpBtn.click()
}
// $("#add_files").after(fastUpBtn).after(triggerUpBtn);
$("#ubbHelp").before(fastUpBtn).before(triggerUpBtn);
// 上传文件
function resolveFileList(files) {
Array.from(files).forEach(file => {
if (file.type.indexOf('text') === 0 || file.name.indexOf('.md') === file.name.length - 3) {
file.text().then(text => {
insertText(content, text)
});
} else {
uploadFile(file);
}
})
}
function insertText(obj, str) {
if (document.selection) {
var sel = document.selection.createRange();
sel.text = str;
} else if (typeof obj.selectionStart === 'number' && typeof obj.selectionEnd === 'number') {
var startPos = obj.selectionStart,
endPos = obj.selectionEnd,
cursorPos = startPos,
tmpStr = obj.value;
obj.value = tmpStr.substring(0, startPos) + str + tmpStr.substring(endPos, tmpStr.length);
cursorPos += str.length;
obj.selectionStart = obj.selectionEnd = cursorPos;
} else {
obj.value += str;
}
}
function Toast(msg, duration) {
console.log(msg)
// 如果不需要提示框,请删除下面的代码
duration = isNaN(duration) ? 2000 : duration;
var m = document.createElement('div');
m.innerHTML = msg;
m.style.cssText = "max-width:60%;min-width: 150px;padding:0 14px;min-height: 40px;color: rgb(255, 255, 255);line-height: 40px;text-align: center;border-radius: 4px;position: fixed;top: 50%;left: 50%;transform: translate(-50%, -50%);z-index: 999999;background: rgba(0, 0, 0,.7);font-size: 16px;";
document.body.appendChild(m);
setTimeout(function () {
var d = 0.5;
m.style.webkitTransition = '-webkit-transform ' + d + 's ease-in, opacity ' + d + 's ease-in';
m.style.opacity = '0';
setTimeout(function () {
document.body.removeChild(m)
}, d * 1000);
}, duration);
// 如果不需要提示框,请删除上面的代码
}
function md5sum(file) {
var blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
var chunkSize = 2097152;
var chunks = Math.ceil(file.size / chunkSize);
var currentChunk = 0;
var spark = new SparkMD5.ArrayBuffer();
var fileReader = new FileReader();
var deferred = $.Deferred();
fileReader.onload = function (e) {
spark.append(e.target.result);
currentChunk++;
if (currentChunk < chunks) {
loadNext();
} else {
deferred.resolve(spark.end());
}
};
fileReader.onerror = function (error) {
deferred.reject(error);
};
function loadNext() {
var start = currentChunk * chunkSize;
var end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
}
loadNext();
return deferred.promise();
}
async function uploadFile(file) {
try {
Toast('计算文件MD5');
var md5 = await md5sum(file);
console.log('md5', md5);
Toast('获取上传凭证');
var uploadForm = await $.post('/q.php/api.upload-form.json', {
name: file.name,
size: file.size,
md5: md5
});
console.log('uploadForm', uploadForm);
if (uploadForm.error) {
Toast(uploadForm.errInfo.message);
return;
}
if (uploadForm.fileExists) {
Toast('已秒传');
insertText(document.getElementById("content"), uploadForm.contentUbb);
return;
}
// 准备表单
var fd = new FormData();
// 填充API返回的内容
for (var k in uploadForm.formData) {
fd.append(k, uploadForm.formData[k]);
}
// 填充待上传的文件
fd.append(uploadForm.fileFieldName, file);
Toast("开始上传");
await $.ajax({
type: uploadForm.method,
url: uploadForm.requestUrl,
data: fd,
processData: false,
contentType: false,
mimeType: uploadForm.enctype,
})
Toast("上传成功");
insertText(document.getElementById("content"), uploadForm.contentUbb);
} catch (ex) {
console.log(ex);
Toast("上传失败\n" + JSON.stringify(ex));
}
}
}); // 【😭😭😭】
/**图文拖拽快传插件结束**/
</script>
嗯,promise的reject用await等待之后会转换为异常,然后就会被下面的catch捕捉到。
.config(237.32 KB)
一加8Pro
一加8Pro
测试
HUAWEI Mate 30 Pro 5G版
小米MIX2s(白)
@唐志华,https://hu60.cn/q.php/bbs.topic.101061.html
OSSAccessKeyId被公开,但是它本身就可以公开,只有它做不了任何事。OSSAccessKeySecret并不会被公开,公开的policy和signature仅提供了上传单个文件的权限(key、文件大小和文件md5被policy限制死,上传内容不相符的文件会失败),并且无法对已经上传的文件进行覆盖,因为如果文件已存在(fileExists: true
),就不会给出policy和signature。
老虎给力,不过上传完的时候不验证返回结果的吗