发布一个工具,截图存本地使用

27 阅读4分钟
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>剪切板图片粘贴工具</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'Microsoft YaHei', Arial, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            padding: 20px;
        }

        .container {
            max-width: 1200px;
            margin: 0 auto;
            background: rgba(255, 255, 255, 0.95);
            border-radius: 20px;
            padding: 30px;
            box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
        }

        .title {
            text-align: center;
            color: #333;
            margin-bottom: 30px;
            font-size: 28px;
            font-weight: 600;
        }

        .paste-area {
            width: 100%;
            height: 300px;
            border: 3px dashed #4CAF50;
            border-radius: 15px;
            display: flex;
            align-items: center;
            justify-content: center;
            background: linear-gradient(45deg, #f8f9fa, #e9ecef);
            cursor: pointer;
            transition: all 0.3s ease;
            margin-bottom: 30px;
            position: relative;
            overflow: hidden;
        }

        .paste-area:hover {
            border-color: #45a049;
            background: linear-gradient(45deg, #e8f5e8, #d4edda);
            transform: translateY(-2px);
            box-shadow: 0 10px 25px rgba(76, 175, 80, 0.2);
        }

        .paste-area.dragover {
            border-color: #2196F3;
            background: linear-gradient(45deg, #e3f2fd, #bbdefb);
            transform: scale(1.02);
        }

        .paste-content {
            text-align: center;
            color: #666;
            font-size: 18px;
        }

        .paste-icon {
            font-size: 48px;
            margin-bottom: 15px;
            display: block;
        }

        .paste-text {
            font-weight: 500;
        }

        .paste-hint {
            font-size: 14px;
            color: #999;
            margin-top: 10px;
        }

        .images-grid {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
            gap: 20px;
            margin-top: 20px;
        }

        .image-item {
            position: relative;
            border-radius: 12px;
            overflow: hidden;
            box-shadow: 0 8px 20px rgba(0, 0, 0, 0.1);
            transition: all 0.3s ease;
            background: white;
            cursor: pointer;
        }

        .image-item:hover {
            transform: translateY(-5px);
            box-shadow: 0 15px 35px rgba(0, 0, 0, 0.2);
        }

        .image-item img {
            width: 100%;
            height: 200px;
            object-fit: cover;
            display: block;
        }

        .image-info {
            padding: 12px;
            background: white;
        }

        .image-name {
            font-size: 14px;
            color: #333;
            font-weight: 500;
            margin-bottom: 5px;
            word-break: break-all;
        }

        .image-time {
            font-size: 12px;
            color: #999;
        }

        .image-actions {
            position: absolute;
            top: 10px;
            right: 10px;
            opacity: 0;
            transition: opacity 0.3s ease;
            display: flex;
            gap: 5px;
        }

        .image-item:hover .image-actions {
            opacity: 1;
        }

        .action-btn {
            width: 32px;
            height: 32px;
            border: none;
            border-radius: 6px;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 16px;
            transition: all 0.2s ease;
        }

        .download-btn {
            background: #4CAF50;
            color: white;
        }

        .download-btn:hover {
            background: #45a049;
            transform: scale(1.1);
        }

        .delete-btn {
            background: #f44336;
            color: white;
        }

        .delete-btn:hover {
            background: #da190b;
            transform: scale(1.1);
        }

        .empty-state {
            text-align: center;
            color: #999;
            font-size: 16px;
            padding: 40px;
            background: #f8f9fa;
            border-radius: 12px;
            margin-top: 20px;
        }

        .stats {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 20px;
            padding: 15px 20px;
            background: linear-gradient(45deg, #e3f2fd, #bbdefb);
            border-radius: 12px;
        }

        .stat-item {
            text-align: center;
        }

        .stat-number {
            font-size: 24px;
            font-weight: 600;
            color: #1976d2;
        }

        .stat-label {
            font-size: 14px;
            color: #666;
            margin-top: 5px;
        }

        .context-menu {
            position: fixed;
            background: white;
            border-radius: 8px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
            padding: 8px 0;
            z-index: 1000;
            min-width: 120px;
            display: none;
        }

        .context-menu-item {
            padding: 10px 16px;
            cursor: pointer;
            display: flex;
            align-items: center;
            gap: 8px;
            font-size: 14px;
            color: #333;
            transition: background-color 0.2s;
        }

        .context-menu-item:hover {
            background: #f5f5f5;
        }

        .context-menu-item.danger {
            color: #f44336;
        }

        .context-menu-item.danger:hover {
            background: #ffebee;
        }

        .notification {
            position: fixed;
            top: 20px;
            right: 20px;
            background: #4CAF50;
            color: white;
            padding: 12px 20px;
            border-radius: 8px;
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
            z-index: 1001;
            transform: translateX(100%);
            transition: transform 0.3s ease;
        }

        .notification.show {
            transform: translateX(0);
        }

        .notification.error {
            background: #f44336;
        }

        @media (max-width: 768px) {
            .container {
                padding: 20px;
                margin: 10px;
            }

            .title {
                font-size: 24px;
            }

            .paste-area {
                height: 200px;
            }

            .images-grid {
                grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
                gap: 15px;
            }

            .stats {
                flex-direction: column;
                gap: 15px;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <h1 class="title">📋 剪切板图片粘贴工具</h1>
        
        <div class="stats">
            <div class="stat-item">
                <div class="stat-number" id="totalCount">0</div>
                <div class="stat-label">总图片数</div>
            </div>
            <div class="stat-item">
                <div class="stat-number" id="totalSize">0</div>
                <div class="stat-label">总大小 (KB)</div>
            </div>
            <div class="stat-item">
                <div class="stat-number" id="lastPaste">--</div>
                <div class="stat-label">最后粘贴</div>
            </div>
        </div>

        <div class="paste-area" id="pasteArea">
            <div class="paste-content">
                <span class="paste-icon">📋</span>
                <div class="paste-text">点击此处或按 Ctrl+V 粘贴图片</div>
                <div class="paste-hint">支持截图、复制图片等</div>
            </div>
        </div>

        <div id="imagesContainer">
            <div class="empty-state" id="emptyState">
                <div style="font-size: 48px; margin-bottom: 15px;">🖼️</div>
                <div>还没有粘贴任何图片</div>
                <div style="font-size: 14px; margin-top: 10px; color: #ccc;">试试按 Ctrl+V 或直接拖拽图片到上方区域</div>
            </div>
        </div>
    </div>

    <!-- 右键菜单 -->
    <div class="context-menu" id="contextMenu">
        <div class="context-menu-item" id="downloadItem">
            <span>📥</span>
            <span>下载图片</span>
        </div>
        <div class="context-menu-item danger" id="deleteItem">
            <span>🗑️</span>
            <span>删除图片</span>
        </div>
    </div>

    <!-- 通知 -->
    <div class="notification" id="notification"></div>

    <script>
        class ClipboardImageManager {
            constructor() {
                this.images = [];
                this.contextMenu = document.getElementById('contextMenu');
                this.notification = document.getElementById('notification');
                this.pasteArea = document.getElementById('pasteArea');
                this.imagesContainer = document.getElementById('imagesContainer');
                this.emptyState = document.getElementById('emptyState');
                this.currentImageId = null;

                this.init();
            }

            init() {
                // 监听粘贴事件
                document.addEventListener('paste', this.handlePaste.bind(this));
                
                // 监听点击事件
                this.pasteArea.addEventListener('click', () => {
                    this.showNotification('请按 Ctrl+V 粘贴图片', 'info');
                });

                // 监听拖拽事件
                this.pasteArea.addEventListener('dragover', this.handleDragOver.bind(this));
                this.pasteArea.addEventListener('dragleave', this.handleDragLeave.bind(this));
                this.pasteArea.addEventListener('drop', this.handleDrop.bind(this));

                // 右键菜单事件
                document.getElementById('downloadItem').addEventListener('click', this.downloadImage.bind(this));
                document.getElementById('deleteItem').addEventListener('click', this.deleteImage.bind(this));

                // 点击其他地方关闭右键菜单
                document.addEventListener('click', () => {
                    this.contextMenu.style.display = 'none';
                });

                // 更新统计信息
                this.updateStats();
            }

            handlePaste(e) {
                e.preventDefault();
                
                const items = e.clipboardData.items;
                for (let item of items) {
                    if (item.type.indexOf('image') !== -1) {
                        const file = item.getAsFile();
                        this.addImage(file);
                        break;
                    }
                }
            }

            handleDragOver(e) {
                e.preventDefault();
                this.pasteArea.classList.add('dragover');
            }

            handleDragLeave(e) {
                e.preventDefault();
                this.pasteArea.classList.remove('dragover');
            }

            handleDrop(e) {
                e.preventDefault();
                this.pasteArea.classList.remove('dragover');
                
                const files = e.dataTransfer.files;
                for (let file of files) {
                    if (file.type.indexOf('image') !== -1) {
                        this.addImage(file);
                    }
                }
            }

            addImage(file) {
                const reader = new FileReader();
                reader.onload = (e) => {
                    const imageData = {
                        id: Date.now() + Math.random(),
                        name: this.generateFileName(),
                        data: e.target.result,
                        file: file,
                        size: file.size,
                        time: new Date()
                    };

                    this.images.unshift(imageData);
                    this.renderImages();
                    this.updateStats();
                    this.showNotification(`成功添加图片: ${imageData.name}`, 'success');
                };
                reader.readAsDataURL(file);
            }

            generateFileName() {
                const now = new Date();
                const year = now.getFullYear();
                const month = String(now.getMonth() + 1).padStart(2, '0');
                const day = String(now.getDate()).padStart(2, '0');
                const hour = String(now.getHours()).padStart(2, '0');
                const minute = String(now.getMinutes()).padStart(2, '0');
                const second = String(now.getSeconds()).padStart(2, '0');
                
                return `${year}-${month}-${day}-${hour}${minute}${second}.png`;
            }

            renderImages() {
                if (this.images.length === 0) {
                    this.imagesContainer.innerHTML = '';
                    this.imagesContainer.appendChild(this.emptyState);
                    return;
                }

                const grid = document.createElement('div');
                grid.className = 'images-grid';

                this.images.forEach(image => {
                    const imageItem = document.createElement('div');
                    imageItem.className = 'image-item';
                    imageItem.dataset.imageId = image.id;

                    imageItem.innerHTML = `
                        <img src="${image.data}" alt="${image.name}" />
                        <div class="image-actions">
                            <button class="action-btn download-btn" onclick="imageManager.downloadImageById('${image.id}')" title="下载">
                                📥
                            </button>
                            <button class="action-btn delete-btn" onclick="imageManager.deleteImageById('${image.id}')" title="删除">
                                🗑️
                            </button>
                        </div>
                        <div class="image-info">
                            <div class="image-name">${image.name}</div>
                            <div class="image-time">${image.time.toLocaleString()}</div>
                        </div>
                    `;

                    // 右键菜单
                    imageItem.addEventListener('contextmenu', (e) => {
                        e.preventDefault();
                        this.currentImageId = image.id;
                        this.showContextMenu(e.clientX, e.clientY);
                    });

                    grid.appendChild(imageItem);
                });

                this.imagesContainer.innerHTML = '';
                this.imagesContainer.appendChild(grid);
            }

            showContextMenu(x, y) {
                this.contextMenu.style.left = x + 'px';
                this.contextMenu.style.top = y + 'px';
                this.contextMenu.style.display = 'block';
            }

            downloadImage() {
                if (this.currentImageId) {
                    this.downloadImageById(this.currentImageId);
                    this.contextMenu.style.display = 'none';
                }
            }

            downloadImageById(imageId) {
                const image = this.images.find(img => img.id == imageId);
                if (!image) return;

                const link = document.createElement('a');
                link.href = image.data;
                link.download = image.name;
                link.style.display = 'none';
                document.body.appendChild(link);
                link.click();
                document.body.removeChild(link);

                this.showNotification(`正在下载: ${image.name}`, 'success');
            }

            deleteImage() {
                if (this.currentImageId) {
                    this.deleteImageById(this.currentImageId);
                    this.contextMenu.style.display = 'none';
                }
            }

            deleteImageById(imageId) {
                const index = this.images.findIndex(img => img.id == imageId);
                if (index === -1) return;

                const image = this.images[index];
                this.images.splice(index, 1);
                this.renderImages();
                this.updateStats();
                this.showNotification(`已删除: ${image.name}`, 'success');
            }

            updateStats() {
                const totalCount = this.images.length;
                const totalSize = Math.round(this.images.reduce((sum, img) => sum + img.size, 0) / 1024);
                const lastPaste = this.images.length > 0 ? this.images[0].time.toLocaleTimeString() : '--';

                document.getElementById('totalCount').textContent = totalCount;
                document.getElementById('totalSize').textContent = totalSize;
                document.getElementById('lastPaste').textContent = lastPaste;
            }

            showNotification(message, type = 'success') {
                this.notification.textContent = message;
                this.notification.className = `notification ${type} show`;
                
                setTimeout(() => {
                    this.notification.classList.remove('show');
                }, 3000);
            }
        }

        // 初始化应用
        const imageManager = new ClipboardImageManager();

        // 全局快捷键
        document.addEventListener('keydown', (e) => {
            if (e.ctrlKey && e.key === 'v') {
                // Ctrl+V 已经被 paste 事件处理
            }
        });

        // 防止默认的拖拽行为
        document.addEventListener('dragover', (e) => e.preventDefault());
        document.addEventListener('drop', (e) => e.preventDefault());
    </script>
</body>
</html>