更好的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, input[type="number"], input[type="text"] {
      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);
    }
    input[type="number"], input[type="text"] {
      color: #000;
      background: #fff;
    }
  </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="容量数值">
    <select id="capacityUnit">
      <option value="KB">KB</option>
      <option value="MB" selected>MB</option>
      <option value="GB">GB</option>
      <option value="TB">TB</option>
    </select>
    <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('setCapacityBtn').addEventListener('click', () => {
      const value = parseFloat(document.getElementById('capacityInput').value);
      const unit = document.getElementById('capacityUnit').value;
      if (isNaN(value) || value <= 0) {
        alert('请输入有效的容量数值');
        return;
      }

      const unitMap = {
        KB: 1 / 1024,
        MB: 1,
        GB: 1024,
        TB: 1024 * 1024
      };
      maxCapacity = value * unitMap[unit];
      updateCapacity();
      alert(`U盘容量已设置为 ${value} ${unit}(约 ${maxCapacity.toFixed(2)} MB)`);
    });

    document.getElementById('backBtn').addEventListener('click', () => {
      if (pathStack.length > 1) {
        pathStack.pop();
        currentPath = pathStack[pathStack.length - 1];
        updatePathDisplay();
        renderFileList();
      } else {
        alert('已在根目录');
      }
    });

    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();
      }
    });

    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>📁 ${item.name}</span>
            <div class="actions">
              <button onclick="enterFolder('${item.path}')">进入</button>
              <button onclick="removeFolder('${item.path}')">删除</button>
            </div>`;
        } else {
          div.innerHTML = `<span>📄 ${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 updatePathDisplay() {
      currentPathDisplay.textContent = `当前位置: ${currentPath === '/' ? '根目录' : currentPath}`;
    }

    function updateCapacity() {
      const percent = Math.min((usedCapacity / maxCapacity) * 100, 100);
      capacityDisplay.textContent = `已用空间: ${usedCapacity.toFixed(2)} MB / ${maxCapacity.toFixed(2)} MB (${percent.toFixed(1)}%)`;
      progressBar.style.width = percent + '%';
      progressBar.textContent = `${percent.toFixed(1)}%`;
    }

    window.enterFolder = function(path) {
      currentPath = path;
      pathStack.push(path);
      updatePathDisplay();
      renderFileList();
    };

    window.previewFile = function(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');
          previewWindow.document.write(`<pre>${e.target.result.slice(0, 2000)}</pre>`);
        };
        reader.readAsText(fileObj.file);
      } else if (fileObj.file.type.includes('image')) {
        const imgWin = window.open('', '_blank');
        imgWin.document.write(`<img src="${URL.createObjectURL(fileObj.file)}" style="max-width:100%;">`);
      } else {
        alert('暂不支持该文件类型预览');
      }
    };

    window.renameFile = function(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 = function(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 = function(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 = function(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>

        
编辑器加载中
预览
控制台