Vue/Rect 生态用多了都快忘记原生js怎么写了,今天需要直接在服务器裸写个页面,实现 textarea 文本框里接收拖拽多个图片,同时能直接粘贴截图上传,使用一些现成的框架倒是分分钟完成,但要直接裸写,还是费了思量。
html中的textarea元素
bash
<textarea id="textarea" placeholder="可拖拽图片到此上传,或截图后在此粘贴"></textarea>
实现思路:
无论是拖拽上传,还是粘贴上传,本质都是使用 FormData 包装 File数据,传递给服务器,关键点是取到File或Blob数据。
在拖拽时,可在 drop
放下动作时,通过event.dataTransfer.files
获取到文件数据。
在粘贴监听 paste
事件时,可通过event.clipboardData.items
获取到剪切板中的第一个Blob数据,然后调用Blog的getAsFile转为File。
再判断他们的mime类型如果是图片,则上传。
先实现上传函数
使用原生xhr实现,无它,简单。
假设服务器返回json格式数据
code=0代表上传成功,返回url地址,code=其他失败,msg字段填充失败信息
javascript
// 接口 File或 Blob类型数据
const uploadimg=function(file){
// 创建 FormData 对象
var formData = new FormData();
// 添加图片文件到表单数据中
formData.append('file', file);
// 创建 XMLHttpRequest 对象
var xhr = new XMLHttpRequest();
// 设置上传完成后的回调函数
xhr.onload = function() {
if (xhr.status == 200) {
try {
// 解析服务器返回的JSON数据 {code:0,msg:msg}
var response = JSON.parse(xhr.responseText);
if (response && response.code === 0) {
} else {
console.error('Error uploading image: ' + response.msg);
}
} catch (e) {
console.error('Error parsing server response as JSON');
}
} else {
console.log('Error uploading image');
}
};
xhr.onerror=function(){
console.log('error')
}
xhr.open('POST', '/index/upload', true);
// 发送图片文件数据
xhr.send(formData);
}
为 textarea 绑定拖拽事件函数
在拖拽进入textarea区域时,动态添加一个outline边框,以便区分。
scss
// 元素
var textArea = document.getElementById('textarea');
// 拖拽到上方时,添加一个 outline 样式
var addOutline = function() {
textArea.style.outline = "2px solid #0000FF";
};
// 松开时,移除outline 样式
var removeOutline = function() {
textArea.style.outline = "";
};
// 当有图片拖拽进入区域时添加outline
textArea.addEventListener('dragenter', function(event) {
event.stopPropagation();
event.preventDefault();
addOutline();
});
// 文件在区域内移动时防止浏览器默认行为
textArea.addEventListener('dragover', function(event) {
event.stopPropagation();
event.preventDefault();
});
// 文件离开区域时移除边框
textArea.addEventListener('dragleave', function(event) {
event.stopPropagation();
event.preventDefault();
removeOutline();
});
// 文件放下时进行处理
textArea.addEventListener('drop', function(event) {
event.stopPropagation();
event.preventDefault();
removeOutline();
// 获取文件列表
var files = event.dataTransfer.files;
if (files.length > 0) {
// 遍历处理所有图片
[].forEach.call(files,function(file){
if(file.type.match('image.*')){
uploadimg(file);
}
})
}
});
绑定粘贴处理函数
再监听 粘贴 事件,获取剪切板中第一个数据。
csharp
// 粘贴处理函数
textArea.addEventListener('paste', function(event) {
// 阻止默认行为
event.preventDefault();
// 只检查第一个数据,是否是图片类型
if (event.clipboardData && event.clipboardData.items) {
var items = event.clipboardData.items;
let i=0;
// 如果找到图片类型
if (items[i].type.indexOf('image') !== -1) {
var blob = items[i].getAsFile();
uploadimg(blob);
}
}
});
}