本文目录导读:

网页端实现(HTML5 + JavaScript)
基础拖拽上传
<!DOCTYPE html>
<html>
<head>
<style>
#dropZone {
width: 400px;
height: 200px;
border: 2px dashed #ccc;
border-radius: 10px;
text-align: center;
line-height: 200px;
font-size: 18px;
color: #666;
transition: all 0.3s;
}
#dropZone.dragover {
border-color: #4CAF50;
background: #e8f5e9;
color: #4CAF50;
}
</style>
</head>
<body>
<div id="dropZone">拖拽文件到这里</div>
<div id="fileList"></div>
<script>
const dropZone = document.getElementById('dropZone');
const fileList = document.getElementById('fileList');
// 防止浏览器默认打开文件
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
dropZone.addEventListener(eventName, (e) => {
e.preventDefault();
e.stopPropagation();
});
});
// 拖拽高亮效果
['dragenter', 'dragover'].forEach(eventName => {
dropZone.addEventListener(eventName, () => {
dropZone.classList.add('dragover');
});
});
['dragleave', 'drop'].forEach(eventName => {
dropZone.addEventListener(eventName, () => {
dropZone.classList.remove('dragover');
});
});
// 处理文件拖放
dropZone.addEventListener('drop', (e) => {
const files = e.dataTransfer.files;
handleFiles(files);
});
function handleFiles(files) {
for (const file of files) {
// 显示文件信息
const div = document.createElement('div');
div.textContent = `${file.name} - ${file.size} bytes - ${file.type}`;
fileList.appendChild(div);
// 这里可以上传文件或做其他处理
console.log('文件信息:', {
name: file.name,
size: file.size,
type: file.type,
lastModified: file.lastModified
});
}
}
</script>
</body>
</html>
带上传功能的完整示例
<!DOCTYPE html>
<html>
<head>
<style>
#dropZone {
width: 500px;
height: 300px;
border: 2px dashed #ccc;
border-radius: 10px;
margin: 20px auto;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
transition: all 0.3s;
}
#dropZone.dragover {
border-color: #2196F3;
background: #E3F2FD;
}
#dropZone .icon {
font-size: 48px;
margin-bottom: 10px;
}
#dropZone .text {
font-size: 16px;
color: #666;
}
.upload-progress {
width: 80%;
margin: 20px auto;
}
.progress-bar {
background: #f0f0f0;
border-radius: 5px;
padding: 3px;
}
.progress-bar-fill {
background: #4CAF50;
border-radius: 5px;
height: 20px;
width: 0%;
transition: width 0.3s;
}
</style>
</head>
<body>
<div id="dropZone">
<div class="icon">📁</div>
<div class="text">拖拽文件到此处上传</div>
</div>
<div id="uploads"></div>
<script>
const dropZone = document.getElementById('dropZone');
// 拖拽事件处理
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
dropZone.addEventListener(eventName, preventDefaults);
});
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
// 高亮效果
['dragenter', 'dragover'].forEach(eventName => {
dropZone.addEventListener(eventName, highlight);
});
['dragleave', 'drop'].forEach(eventName => {
dropZone.addEventListener(eventName, unhighlight);
});
function highlight() {
dropZone.classList.add('dragover');
}
function unhighlight() {
dropZone.classList.remove('dragover');
}
// 处理文件拖放
dropZone.addEventListener('drop', handleDrop);
function handleDrop(e) {
const data = e.dataTransfer;
const files = data.files;
// 检查是否有文件
if (files.length) {
// 检查文件类型(可选)
const validFiles = [...files].filter(file => {
// 这里可以添加文件类型限制
// 只接受图片
// return file.type.startsWith('image/');
return true;
});
validFiles.forEach(uploadFile);
}
}
// 模拟文件上传
function uploadFile(file) {
const uploads = document.getElementById('uploads');
const uploadItem = document.createElement('div');
uploadItem.className = 'upload-item';
uploadItem.innerHTML = `
<div>${file.name} (${formatFileSize(file.size)})</div>
<div class="upload-progress">
<div class="progress-bar">
<div class="progress-bar-fill"></div>
</div>
</div>
<div class="status">上传中...</div>
`;
uploads.appendChild(uploadItem);
// 模拟上传进度
let progress = 0;
const fillBar = uploadItem.querySelector('.progress-bar-fill');
const status = uploadItem.querySelector('.status');
const interval = setInterval(() => {
progress += 10;
fillBar.style.width = progress + '%';
if (progress >= 100) {
clearInterval(interval);
status.textContent = '✅ 上传完成';
fillBar.style.background = '#4CAF50';
}
}, 100);
// 实际项目中这里应该使用 FormData 和 fetch/XMLHttpRequest
// const formData = new FormData();
// formData.append('file', file);
// fetch('/upload', { method: 'POST', body: formData });
}
function formatFileSize(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
</script>
</body>
</html>
Electron 桌面应用(Node.js + HTML)
// main.js (Electron 主进程)
const { app, BrowserWindow, ipcMain } = require('electron');
const path = require('path');
const fs = require('fs');
function createWindow() {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
preload: path.join(__dirname, 'preload.js')
}
});
win.loadFile('index.html');
}
app.whenReady().then(createWindow);
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<style>
#dropZone {
width: 100%;
height: 400px;
border: 2px dashed #4CAF50;
border-radius: 10px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: 20px;
color: #4CAF50;
}
#dropZone.dragover {
background: #E8F5E9;
}
.file-list {
margin-top: 20px;
padding: 15px;
}
.file-item {
background: #f5f5f5;
margin: 5px 0;
padding: 10px;
border-radius: 5px;
display: flex;
justify-content: space-between;
align-items: center;
}
.file-info {
color: #666;
}
.save-btn {
background: #4CAF50;
color: white;
border: none;
padding: 5px 10px;
border-radius: 3px;
cursor: pointer;
}
</style>
</head>
<body>
<div id="dropZone">
🖱️ 拖拽文件到这里
</div>
<div id="fileList" class="file-list"></div>
<script>
const dropZone = document.getElementById('dropZone');
const fileList = document.getElementById('fileList');
const droppedFiles = [];
// 拖拽事件处理
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
dropZone.addEventListener(eventName, (e) => {
e.preventDefault();
e.stopPropagation();
});
});
// 高亮效果
['dragenter', 'dragover'].forEach(eventName => {
dropZone.addEventListener(eventName, () => {
dropZone.classList.add('dragover');
});
});
['dragleave', 'drop'].forEach(eventName => {
dropZone.addEventListener(eventName, () => {
dropZone.classList.remove('dragover');
});
});
// 处理文件拖放
dropZone.addEventListener('drop', async (e) => {
const items = e.dataTransfer.items;
for (const item of items) {
if (item.kind === 'file') {
// 获取文件对象
const file = item.getAsFile();
droppedFiles.push(file);
const div = document.createElement('div');
div.className = 'file-item';
div.innerHTML = `
<div>
<strong>${file.name}</strong>
<div class="file-info">
大小: ${(file.size / 1024).toFixed(2)} KB |
类型: ${file.type || '未知'} |
修改时间: ${new Date(file.lastModified).toLocaleDateString()}
</div>
</div>
<button class="save-btn" onclick="saveFile('${file.name}')">保存</button>
`;
fileList.appendChild(div);
}
}
});
// 保存文件到指定位置
async function saveFile(fileName) {
const file = droppedFiles.find(f => f.name === fileName);
if (file) {
try {
// 使用 Electron 的 dialog 选择保存位置
const result = await window.electronAPI.saveFile(fileName);
if (result.success) {
// 将文件内容写入
const reader = new FileReader();
reader.onload = async (e) => {
await window.electronAPI.writeFile(result.path, e.target.result);
alert('文件保存成功:' + result.path);
};
reader.readAsDataURL(file);
}
} catch (error) {
console.error('保存失败:', error);
alert('保存失败:' + error.message);
}
}
}
</script>
</body>
</html>
// preload.js (Electron 预加载脚本)
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electronAPI', {
// 获取文件信息
getFilePath: (file) => ipcRenderer.invoke('get-file-path', file),
// 保存文件
saveFile: (fileName) => ipcRenderer.invoke('save-file', fileName),
// 写入文件内容
writeFile: (path, data) => ipcRenderer.invoke('write-file', { path, data })
});
Python 桌面应用(Tkinter / PyQt)
Tkinter 版本
import tkinter as tk
from tkinter import ttk
from tkinterdnd2 import DND_FILES, TkinterDnD
class DragDropApp(TkinterDnD.Tk):
def __init__(self):
super().__init__()
self.title("文件拖拽处理")
self.geometry("500x400")
# 创建拖拽区域
self.drop_zone = tk.Label(
self,
text="📁 拖拽文件到这里",
bg="#f0f0f0",
relief="solid",
borderwidth=2,
font=("Arial", 16)
)
self.drop_zone.pack(pady=20, padx=20, fill="both", expand=True)
# 注册拖拽事件
self.drop_zone.drop_target_register(DND_FILES)
self.drop_zone.dnd_bind('<<Drop>>', self.on_drop)
self.drop_zone.dnd_bind('<<DragEnter>>', self.on_drag_enter)
self.drop_zone.dnd_bind('<<DragLeave>>', self.on_drag_leave)
# 文件列表
self.file_list = tk.Listbox(self, height=10)
self.file_list.pack(pady=10, padx=20, fill="both", expand=True)
# 处理按钮
btn_frame = tk.Frame(self)
btn_frame.pack(pady=10)
tk.Button(btn_frame, text="处理文件", command=self.process_files).pack(side="left", padx=5)
tk.Button(btn_frame, text="清空列表", command=self.clear_list).pack(side="left", padx=5)
self.files = []
def on_drag_enter(self, event):
self.drop_zone.config(bg="#e8f5e9", relief="solid")
def on_drag_leave(self, event):
self.drop_zone.config(bg="#f0f0f0")
def on_drop(self, event):
self.drop_zone.config(bg="#f0f0f0")
# 解析拖拽的文件路径
files = self.tk.splitlist(event.data)
for file in files:
self.files.append(file)
self.file_list.insert("end", file)
def process_files(self):
if not self.files:
print("没有文件需要处理")
return
# 这里添加具体的文件处理逻辑
for file in self.files:
print(f"正在处理: {file}")
# 示例:获取文件大小
import os
size = os.path.getsize(file)
print(f" 文件大小: {size} bytes")
print("文件处理完成!")
def clear_list(self):
self.files.clear()
self.file_list.delete(0, "end")
if __name__ == "__main__":
app = DragDropApp()
app.mainloop()
PyQt5 版本
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QVBoxLayout, QWidget, QPushButton, QListWidget, QMessageBox
from PyQt5.QtCore import Qt, QUrl
from PyQt5.QtGui import QDragEnterEvent, QDropEvent
class DragDropWindow(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle("文件拖拽处理")
self.setGeometry(100, 100, 500, 400)
# 主部件设置
central_widget = QWidget()
self.setCentralWidget(central_widget)
layout = QVBoxLayout()
central_widget.setLayout(layout)
# 拖拽区域
self.drop_label = QLabel(
"📁 拖拽文件到这里\n\n支持多文件选择",
self
)
self.drop_label.setAlignment(Qt.AlignCenter)
self.drop_label.setStyleSheet("""
QLabel {
border: 2px dashed #4CAF50;
border-radius: 10px;
padding: 40px;
font-size: 16px;
background: #f0f0f0;
}
""")
layout.addWidget(self.drop_label)
# 文件列表
self.file_list = QListWidget()
layout.addWidget(self.file_list)
# 按钮
process_btn = QPushButton("处理文件", self)
process_btn.clicked.connect(self.process_files)
layout.addWidget(process_btn)
# 启用拖拽
self.setAcceptDrops(True)
self.files = []
def dragEnterEvent(self, event: QDragEnterEvent):
if event.mimeData().hasUrls():
event.accept()
self.drop_label.setStyleSheet("""
QLabel {
border: 2px dashed #2196F3;
border-radius: 10px;
padding: 40px;
font-size: 16px;
background: #E3F2FD;
}
""")
else:
event.ignore()
def dragLeaveEvent(self, event):
self.drop_label.setStyleSheet("""
QLabel {
border: 2px dashed #4CAF50;
border-radius: 10px;
padding: 40px;
font-size: 16px;
background: #f0f0f0;
}
""")
def dropEvent(self, event: QDropEvent):
self.drop_label.setStyleSheet("""
QLabel {
border: 2px dashed #4CAF50;
border-radius: 10px;
padding: 40px;
font-size: 16px;
background: #f0f0f0;
}
""")
files = [url.toLocalFile() for url in event.mimeData().urls()]
for file in files:
if file: # 确保不是空路径
self.files.append(file)
self.file_list.addItem(file)
def process_files(self):
if not self.files:
QMessageBox.warning(self, "提示", "请先拖入文件")
return
# 这里添加你的文件处理逻辑
for file in self.files:
import os
if os.path.isfile(file):
size = os.path.getsize(file)
print(f"处理文件: {file} (大小: {size} bytes)")
QMessageBox.information(self, "成功", "文件处理完成!")
if __name__ == '__main__':
app = QApplication(sys.argv)
window = DragDropWindow()
window.show()
sys.exit(app.exec_())
网页端
- 使用
dragenter、dragover、drop事件 - 必须调用
e.preventDefault()阻止默认行为 - 通过
e.dataTransfer.files获取文件 - 支持多文件拖拽
Electron
- 结合 HTML5 和 Node.js
- 可通过 IPC 与主进程通信
- 可访问文件系统进行保存等操作
Python 桌面
- Tkinter 需要安装
tkinterdnd2 - PyQt5 原生支持拖拽
- 事件处理类似 Web
选择哪种方案取决于你的具体需求(Web 应用、桌面应用、跨平台等)。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播