U盘模拟器edit icon

作者:
邓朝元
Fork(复制)
下载
嵌入
BUG反馈
index.html
现在支持上传本地图片了!
index.html
            
            <!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>U盘模拟器(多主题版)</title>
    <style>
        :root {
            --bg-color: #ffffff;
            --text-color: #333;
            --card-bg: #f9f9f9;
            --button-bg: #4caf50;
            --button-text: #fff;
            --border-color: #ddd;
        }
        [data-theme="dark"] {
            --bg-color: #121212;
            --text-color: #e0e0e0;
            --card-bg: #1f1f1f;
            --button-bg: #2196f3;
            --button-text: #fff;
            --border-color: #444;
        }
        [data-theme="blue"] {
            --bg-color: #e3f2fd;
            --text-color: #0d47a1;
            --card-bg: #bbdefb;
            --button-bg: #0d47a1;
            --button-text: #fff;
            --border-color: #90caf9;
        }
        [data-theme="purple"] {
            --bg-color: #f3e5f5;
            --text-color: #4a148c;
            --card-bg: #e1bee7;
            --button-bg: #9c27b0;
            --button-text: #fff;
            --border-color: #ce93d8;
        }
        [data-theme="green"] {
            --bg-color: #e8f5e9;
            --text-color: #1b5e20;
            --card-bg: #c8e6c9;
            --button-bg: #2e7d32;
            --button-text: #fff;
            --border-color: #a5d6a7;
        }
        [data-theme="orange"] {
            --bg-color: #fff3e0;
            --text-color: #e65100;
            --card-bg: #ffe0b2;
            --button-bg: #ef6c00;
            --button-text: #fff;
            --border-color: #ffb74d;
        }
        [data-theme="pink"] {
            --bg-color: #fce4ec;
            --text-color: #880e4f;
            --card-bg: #f8bbd0;
            --button-bg: #c2185b;
            --button-text: #fff;
            --border-color: #f48fb1;
        }
        [data-theme="gray"] {
            --bg-color: #f5f5f5;
            --text-color: #212121;
            --card-bg: #e0e0e0;
            --button-bg: #607d8b;
            --button-text: #fff;
            --border-color: #9e9e9e;
        }
        body {
            background: var(--bg-color);
            color: var(--text-color);
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 960px;
            margin: 30px auto;
            padding: 20px;
            border: 1px solid var(--border-color);
            border-radius: 12px;
            box-shadow: 0 4px 15px rgba(0,0,0,0.1);
            transition: all 0.3s ease;
        }
        h1 {
            text-align: center;
            margin-bottom: 20px;
        }
        .control-section {
            display: flex;
            flex-wrap: wrap;
            gap: 10px;
            justify-content: center;
            margin-bottom: 15px;
        }
        #currentPath {
            text-align: center;
            margin: 10px 0;
            font-weight: bold;
        }
        #file-list {
            margin-top: 20px;
        }
        .file-item {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 10px;
            border: 1px solid var(--border-color);
            background: var(--card-bg);
            border-radius: 8px;
            margin-bottom: 10px;
            transition: transform 0.2s;
        }
        .file-item:hover {
            transform: scale(1.02);
        }
        .actions {
            display: flex;
            gap: 5px;
            flex-wrap: wrap;
        }
        .capacity {
            text-align: center;
            margin-top: 15px;
            font-weight: bold;
        }
        .progress-bar {
            width: 100%;
            background: #eee;
            border-radius: 5px;
            overflow: hidden;
            margin-top: 10px;
        }
        .progress {
            height: 24px;
            background: var(--button-bg);
            text-align: center;
            color: var(--button-text);
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 0.9em;
            transition: width 0.3s ease;
        }
        button, select {
            cursor: pointer;
            padding: 6px 12px;
            border: none;
            border-radius: 6px;
            background: var(--button-bg);
            color: var(--button-text);
            transition: all 0.3s ease;
        }
        button:hover, select:hover {
            opacity: 0.9;
            transform: translateY(-2px);
        }
    </style>
</head>
<body>
    <h1>U盘模拟器</h1>
    <div class="control-section">
        <input type="file" id="fileInput" multiple>
        <input type="text" id="folderNameInput" placeholder="新建文件夹名称">
        <button id="createFolderBtn">新建文件夹</button>
    </div>
    <div class="control-section">
        <input type="number" id="capacityInput" placeholder="容量 (MB)" min="100" step="50">
        <button id="setCapacityBtn">设置容量</button>
        <button id="backBtn">返回上一级</button>
        <button id="formatBtn">格式化U盘</button>
        <select id="themeSelector">
            <option value="light">白天模式</option>
            <option value="dark">夜晚模式</option>
            <option value="blue">蓝色主题</option>
            <option value="purple">紫色主题</option>
            <option value="green">绿色主题</option>
            <option value="orange">橙色主题</option>
            <option value="pink">粉色主题</option>
            <option value="gray">灰色主题</option>
        </select>
    </div>
    <div id="currentPath">当前位置: 根目录</div>
    <div id="file-list"></div>
    <div class="capacity" id="capacity">已用空间: 0 MB / 500 MB</div>
    <div class="progress-bar">
        <div class="progress" id="progress">0%</div>
    </div>
 
    <script>
        let maxCapacity = 500;
        let usedCapacity = 0;
        const fileSystem = { '/': [] };
        let currentPath = '/';
        const pathStack = ['/'];
 
        const fileList = document.getElementById('file-list'); 
        const capacityDisplay = document.getElementById('capacity'); 
        const progressBar = document.getElementById('progress'); 
        const currentPathDisplay = document.getElementById('currentPath'); 
 
        // 初始化时读取存储的主题偏好 
        document.addEventListener('DOMContentLoaded',  () => {
            const savedTheme = localStorage.getItem('usbTheme')  || 'light';
            document.body.setAttribute('data-theme',  savedTheme);
            document.getElementById('themeSelector').value  = savedTheme;
        });
 
        document.getElementById('themeSelector').addEventListener('change',  (e) => {
            document.body.setAttribute('data-theme',  e.target.value); 
            localStorage.setItem('usbTheme',  e.target.value); 
        });
 
        document.getElementById('fileInput').addEventListener('change',  (e) => {
            Array.from(e.target.files).forEach(file  => addFile(file));
            e.target.value  = '';
        });
 
        document.getElementById('createFolderBtn').addEventListener('click',  () => {
            const folderName = document.getElementById('folderNameInput').value.trim(); 
            if (!folderName) return alert('请输入文件夹名称');
            const folderPath = `${currentPath}${folderName}/`;
            if (fileSystem[folderPath]) return alert('该文件夹已存在');
            fileSystem[folderPath] = [];
            fileSystem[currentPath].push({ type: 'folder', name: folderName, path: folderPath });
            renderFileList();
            document.getElementById('folderNameInput').value  = '';
        });
 
        document.getElementById('formatBtn').addEventListener('click',  () => {
            if (confirm('确定要格式化U盘吗?所有文件将被删除!')) {
                Object.keys(fileSystem).forEach(key  => delete fileSystem[key]);
                fileSystem['/'] = [];
                usedCapacity = 0;
                currentPath = '/';
                pathStack.length  = 1;
                updateCapacity();
                renderFileList();
                updatePathDisplay();
            }
        });
 
        document.getElementById('setCapacityBtn').addEventListener('click',  () => {
            const newCapacity = parseInt(document.getElementById('capacityInput').value); 
            if (isNaN(newCapacity) || newCapacity < 100) {
                alert('请输入有效的容量(最少100MB)');
                return;
            }
            maxCapacity = newCapacity;
            updateCapacity();
            alert(`U盘容量已设置为 ${maxCapacity} MB`);
        });
 
        document.getElementById('backBtn').addEventListener('click',  () => {
            if (pathStack.length  > 1) {
                pathStack.pop(); 
                currentPath = pathStack[pathStack.length - 1];
                updatePathDisplay();
                renderFileList();
            } else {
                alert('已在根目录');
            }
        });
 
        function addFile(file) {
            const fileSizeMB = (file.size  / (1024 * 1024)).toFixed(2);
            if (usedCapacity + parseFloat(fileSizeMB) > maxCapacity) {
                alert(`无法添加文件 ${file.name} ,容量不足。`);
                return;
            }
            usedCapacity += parseFloat(fileSizeMB);
            fileSystem[currentPath].push({ type: 'file', file, sizeMB: fileSizeMB });
            updateCapacity();
            renderFileList();
        }
 
        function renderFileList() {
            fileList.innerHTML  = '';
            fileSystem[currentPath].forEach(item => {
                const div = document.createElement('div'); 
                div.className  = 'file-item';
                if (item.type  === 'folder') {
                    div.innerHTML  = `<span class="file-name">📁 ${item.name}</span> 
                        <div class="actions">
                            <button onclick="enterFolder('${item.path}')"> 进入</button>
                            <button onclick="removeFolder('${item.path}')"> 删除</button>
                        </div>`;
                } else {
                    div.innerHTML  = `<span class="file-name">📄 ${item.file.name}  (${item.sizeMB}  MB)</span>
                        <div class="actions">
                            <button onclick="previewFile('${item.file.name}')"> 预览</button>
                            <button onclick="downloadFile('${item.file.name}')"> 下载</button>
                            <button onclick="renameFile('${item.file.name}')"> 重命名</button>
                            <button onclick="removeFile('${item.file.name}')"> 删除</button>
                        </div>`;
                }
                fileList.appendChild(div); 
            });
        }
 
        function enterFolder(path) {
            currentPath = path;
            pathStack.push(path); 
            updatePathDisplay();
            renderFileList();
        }
 
        function updatePathDisplay() {
            currentPathDisplay.textContent  = `当前位置: ${currentPath === '/' ? '根目录' : currentPath}`;
        }
 
        function updateCapacity() {
            const percent = Math.min((usedCapacity  / maxCapacity) * 100, 100);
            capacityDisplay.textContent  = `已用空间: ${usedCapacity.toFixed(2)}  MB / ${maxCapacity} MB (${percent.toFixed(1)}%)`; 
            progressBar.style.width  = percent + '%';
            progressBar.textContent  = `${percent.toFixed(1)}%`; 
        }
 
        // 全局函数声明 
        window.previewFile  = (fileName) => {
            const fileObj = fileSystem[currentPath].find(item => item.type  === 'file' && item.file.name  === fileName);
            if (!fileObj) return alert('文件未找到');
            
            const reader = new FileReader();
            if (fileObj.file.type.includes('text'))  {
                reader.onload  = e => {
                    const previewWindow = window.open('',  '_blank', 'width=600,height=400');
                    previewWindow.document.write(` 
                        <html>
                            <head><title>预览: ${fileName}</title></head>
                            <body style="font-family: monospace; padding: 20px;">
                                <h2>${fileName}</h2>
                                <pre>${e.target.result.slice(0,  2000)}</pre>
                            </body>
                        </html>
                    `);
                };
                reader.readAsText(fileObj.file); 
            } else if (fileObj.file.type.includes('image'))  {
                const imgWin = window.open('',  '_blank');
                imgWin.document.write(` 
                    <html>
                        <head><title>预览: ${fileName}</title></head>
                        <body style="margin: 0; text-align: center;">
                            <img src="${URL.createObjectURL(fileObj.file)}"  style="max-height: 90vh; max-width: 100%; margin-top: 20px;">
                        </body>
                    </html>
                `);
            } else {
                alert('暂不支持该文件类型的预览,请下载后查看');
            }
        };
 
        window.renameFile  = (fileName) => {
            const idx = fileSystem[currentPath].findIndex(item => item.type  === 'file' && item.file.name  === fileName);
            if (idx === -1) return alert('文件未找到');
            const newName = prompt('请输入新的文件名(包含扩展名):', fileName);
            if (newName && newName.trim())  {
                const oldFile = fileSystem[currentPath][idx].file;
                const newFile = new File([oldFile], newName, { type: oldFile.type  });
                fileSystem[currentPath][idx].file = newFile;
                renderFileList();
            }
        };
 
        window.downloadFile  = (fileName) => {
            const fileObj = fileSystem[currentPath].find(item => item.type  === 'file' && item.file.name  === fileName);
            if (!fileObj) return alert('文件未找到');
            const url = URL.createObjectURL(fileObj.file); 
            const a = document.createElement('a'); 
            a.href  = url;
            a.download  = fileObj.file.name; 
            document.body.appendChild(a); 
            a.click(); 
            document.body.removeChild(a); 
            URL.revokeObjectURL(url); 
        };
 
        window.removeFile  = (fileName) => {
            const idx = fileSystem[currentPath].findIndex(item => item.type  === 'file' && item.file.name  === fileName);
            if (idx !== -1) {
                usedCapacity -= parseFloat(fileSystem[currentPath][idx].sizeMB);
                fileSystem[currentPath].splice(idx, 1);
                updateCapacity();
                renderFileList();
            }
        };
 
        window.removeFolder  = (folderPath) => {
            if (confirm(`确定要删除文件夹 ${folderPath} 及其所有内容吗?`)) {
                // 计算文件夹内文件总大小 
                const folderSize = calculateFolderSize(folderPath);
                usedCapacity -= folderSize;
                
                // 删除文件夹内容 
                Object.keys(fileSystem)  
                    .filter(path => path.startsWith(folderPath)) 
                    .forEach(path => delete fileSystem[path]);
                
                // 从父目录移除 
                const parentPath = folderPath.substring(0,  folderPath.lastIndexOf('/',  folderPath.length  - 2) + 1);
                const idx = fileSystem[parentPath].findIndex(item => item.path  === folderPath);
                if (idx !== -1) fileSystem[parentPath].splice(idx, 1);
                
                updateCapacity();
                renderFileList();
            }
        };
 
        function calculateFolderSize(path) {
            let totalSize = 0;
            Object.keys(fileSystem).forEach(key  => {
                if (key.startsWith(path))  {
                    fileSystem[key].forEach(item => {
                        if (item.type  === 'file') {
                            totalSize += parseFloat(item.sizeMB); 
                        }
                    });
                }
            });
            return totalSize;
        }
    </script>
</body>
</html>
        
编辑器加载中
预览
控制台