UNPKG

dev-server-cli

Version:

Quickly start a local service to implement testing and file transfer

168 lines (157 loc) 5.54 kB
<!-- 创建一个静态的视图文件,使用原生html+css+js实现,不使用任何框架 1. 获取数据:从"/api/list"接口获取目录列表,返回的数据分为文件和目录两种类型,带有一个isDir属性,表示是否是目录 2. 渲染数据:使用原生html+css+js实现,不使用任何框架,文件类型显示文件图标与名称,目录类型显示文件夹图标与名称并带有下划线 3. 添加点击事件:点击文件时加载子级目录,通过带上当前目录参数"/api/list?dir=当前目录"获取子级目录列表,点击文件时调用浏览器下载文件 4. 添加拖拽事件:拖拽文件时上传文件,上传文件时调用"/api/upload"接口,上传文件时带上当前目录参数"/api/upload?dir=当前目录" --> <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <title>目录浏览器</title> <style> body { font-family: Arial, sans-serif; margin: 0; padding: 0; background: #f7f7f7; } #container { max-width: 800px; margin: 40px auto; background: #fff; border-radius: 8px; box-shadow: 0 2px 8px #ccc; padding: 24px; } h2 { margin-top: 0; } ul { list-style: none; padding: 0; } li { display: flex; align-items: center; padding: 8px 0; cursor: pointer; } li.dir { text-decoration: underline; color: #0070f3; } li.file { color: #333; } .icon { width: 20px; height: 20px; margin-right: 10px; } #upload { margin: 16px 0; padding: 8px; border: 1px dashed #aaa; border-radius: 4px; background: #fafafa; text-align: center; } </style> </head> <body> <div id="container"> <h2>目录浏览器</h2> <div id="upload">拖拽文件到此处上传或 <span id="upload-btn" style="color:#0070f3;text-decoration:underline;cursor:pointer;">点击选择文件</span><input type="file" id="upload-input" style="display:none" multiple></div> <ul id="list"></ul> </div> <script> let currentDir = ''; function fetchList(dir = '') { fetch(`/api/files${dir ? '?dir=' + encodeURIComponent(dir) : ''}`) .then(res => res.json()) .then(data => renderList(data, dir)); } function renderList(list, dir) { currentDir = dir; const ul = document.getElementById('list'); ul.innerHTML = ''; // 添加返回上级目录链接 if (dir) { const liUp = document.createElement('li'); liUp.className = 'dir'; liUp.innerHTML = '<span class="icon">⬆️</span>...'; liUp.onclick = () => { const parent = dir.lastIndexOf('/') > -1 ? dir.substring(0, dir.lastIndexOf('/')) : ''; fetchList(parent); }; ul.appendChild(liUp); } list.forEach(item => { const li = document.createElement('li'); li.className = item.isDir ? 'dir' : 'file'; li.innerHTML = item.isDir ? `<span class="icon">📁</span>${item.name}` : `<span class="icon">📄</span>${item.name}`; li.onclick = () => { if (item.isDir) { fetchList(dir ? dir + '/' + item.name : item.name); } else { window.location.href = item.downloadUrl || '/'; } }; ul.appendChild(li); }); } document.getElementById('upload').addEventListener('dragover', e => { e.preventDefault(); e.dataTransfer.dropEffect = 'copy'; }); document.getElementById('upload').addEventListener('drop', e => { e.preventDefault(); const files = e.dataTransfer.files; if (files.length === 0) return; const formData = new FormData(); for (let i = 0; i < files.length; i++) { formData.append('file', files[i]); } fetch(`/api/files?dir=${encodeURIComponent(currentDir)}`, { method: 'POST', body: formData }).then(res => { if (res.ok) { fetchList(currentDir); } else { alert(`上传失败`); } }); }); // 支持点击选择文件上传 document.getElementById('upload-btn').addEventListener('click', function() { document.getElementById('upload-input').click(); }); document.getElementById('upload-input').addEventListener('change', function(e) { const files = e.target.files; if (files.length === 0) return; const formData = new FormData(); for (let i = 0; i < files.length; i++) { formData.append('file', files[i]); } fetch(`/api/files?dir=${encodeURIComponent(currentDir)}`, { method: 'POST', body: formData }).then(res => { if (res.ok) { fetchList(currentDir); } else { alert('上传失败'); } }); // 清空 input,避免同名文件无法重复上传 e.target.value = ''; }); fetchList(); </script> </body> </html>