前端技术(28) : 拖拽、粘贴和点击浏览文件上传
基于静态的vue及element-ui, 下载参考: 前端技术(27) : 纯HTML使用Element UI_html引入element ui-CSDN博客
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>拖拽浏览粘贴上传文件</title>
<link rel="stylesheet" href="element-ui/theme-chalk/index.css">
<style>
/*文件上传*/
#drop-area {
border: 2px dashed #ccc;
border-radius: 10px;
width: 300px;
padding: 20px;
text-align: center;
margin: 50px auto;
}
.gallery-item {
position: relative;
display: inline-block;
margin: 10px;
border: 1px solid #ddd;
border-radius: 5px;
padding: 5px;
background-color: white;
}
.thumb {
width: 100px;
height: auto;
border-radius: 5px;
}
.delete-btn {
position: absolute;
top: 5px;
right: 5px;
cursor: pointer;
color: red;
font-size: 16px;
background-color: rgba(255, 255, 255, 0.7);
border-radius: 50%;
width: 20px;
height: 20px;
display: flex;
justify-content: center;
align-items: center;
}
.file-info {
text-align: center;
white-space: pre-wrap;
}
/* 图片点击放大 */
.overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.7);
display: none;
justify-content: center;
align-items: center;
z-index: 9999;
}
.overlay img {
max-width: 90%;
max-height: 90%;
cursor: pointer;
}
</style>
</head>
<body>
<div class="overlay" onclick="closeOverlay()">
<img id="enlargedImg" src="">
</div>
<div id="app">
<div>
<div id="drop-area" style="width: 800px;height: 300px;">
<br><br><br><br><br>
粘贴文件到这里、
或拖拽文件到这里<br><br>或<span style="color: blue;cursor: pointer;" onclick="selectFile()">选择文件</span>
<input type="file" id="fileElem" multiple onchange="handleFiles(this.files)" style="display:none">
</div>
<div id="gallery"></div>
</div>
</div>
</body>
<script src="js/vue.js"></script>
<script src="element-ui/index.js"></script>
<script src="js/axios.min.js"></script>
<script src="js/jquery-latest.js"></script>
<script>
host = 'http://127.0.0.1:7001'
function c(data) {
console.log(data)
}
var vue = new Vue({
el: '#app',
data() {
return {}
},
created() {},
methods: {
initLoading() {
this.loadingInstance = this.$loading({
lock: true,
text: '加载中',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)',
});
},
showLoading() {
this.initLoading();
},
hideLoading() {
if (this.loadingInstance) {
this.loadingInstance.close()
this.loadingInstance = null
}
}
}
})
// 文件上传
// 文件上传
const dropArea = document.getElementById('drop-area');
const fileElem = document.getElementById('fileElem');
const gallery = document.getElementById('gallery');
var filesMap = new Map();
var fileNameItemMap = new Map();
// 拖拽相关事件处理
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
dropArea.addEventListener(eventName, preventDefaults, false);
});
function selectFile() {
fileElem.click()
}
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
dropArea.addEventListener('drop', handleDrop, false);
function handleDrop(e) {
let dt = e.dataTransfer;
let files = dt.files;
handleFiles(files);
}
function handleFiles(files) {
vue.showLoading();
[...files].forEach(uploadFile);
vue.hideLoading();
c(filesMap)
}
function uploadFile(file) {
let reader = new FileReader();
const formData = new FormData();
formData.append('file', file);
const xhr = new XMLHttpRequest();
xhr.open('POST', host + '/api/upload', true); // 替换为你的后端API地址
xhr.onload = function() {
if (xhr.status === 200) {
const jsonResponse = JSON.parse(xhr.responseText).data;
filesMap.set(jsonResponse.file_name, jsonResponse.url)
history_item = fileNameItemMap.get(file.name)
if (history_item != null) {
gallery.removeChild(history_item);
fileNameItemMap.delete(file.name)
}
let item = document.createElement('div');
fileNameItemMap.set(file.name, item)
item.className = "gallery-item";
if (file.type.match('image.*')) {
let img = document.createElement('img');
img.src = jsonResponse.url;
img.title = file.name;
img.style.cursor = 'pointer';
img.className = "thumb";
item.appendChild(img);
img.onclick = function() {
enlargeImage(jsonResponse.url)
};
} else {
let fileInfo = document.createElement("div");
fileInfo.style.cursor = 'pointer';
fileInfo.className = "file-info";
fileInfo.textContent = file.name + ' ';
// 添加点击事件监听器
fileInfo.addEventListener('click', function() {
// 在新标签页打开指定URL
window.open(jsonResponse.url, '_blank');
});
item.appendChild(fileInfo);
}
let deleteBtn = document.createElement('span');
deleteBtn.className = 'delete-btn';
deleteBtn.textContent = '×';
deleteBtn.onclick = function() {
removeItem(item, file);
};
item.appendChild(deleteBtn);
gallery.appendChild(item);
vue.fileName = [...fileNameItemMap.keys()].join('|')
} else {
console.log('An error occurred during the transaction');
}
};
xhr.send(formData);
}
function getFormattedDateTime() {
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0'); // 月份从0开始,所以要加1
const day = String(now.getDate()).padStart(2, '0');
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
const seconds = String(now.getSeconds()).padStart(2, '0');
return `${year}${month}${day}${hours}${minutes}${seconds}`;
}
// 处理粘贴事件
document.body.addEventListener('paste', function(event) {
for (let i = 0; i < event.clipboardData.items.length; i++) {
let item = event.clipboardData.items[i];
if (item.kind === 'file') {
let file = item.getAsFile();
console.log(file.name)
if(file.name === 'image.png'){
let newFile = new File([file], getFormattedDateTime() + '.png', {
type: file.type
});
uploadFile(newFile);
}else{
uploadFile(file);
}
}
}
});
function removeItem(item, file) {
gallery.removeChild(item);
fileNameItemMap.delete(file.name);
vue.fileName = [...fileNameItemMap.keys()].join('|');
filesMap.delete(file.name);
}
function enlargeImage(img) {
var overlay = document.querySelector(".overlay");
var enlargedImg = document.getElementById("enlargedImg");
enlargedImg.src = img;
overlay.style.display = "flex";
}
function closeOverlay() {
var overlay = document.querySelector(".overlay");
overlay.style.display = "none";
}
</script>
</html>
接口(python)
python(26) : 文件上传及下载和预览-CSDN博客