HTML原生不支持文件夹上传自动展开,需用JavaScript通过webkitdirectory属性读取FileList并解析webkitRelativePath还原路径;但该属性非标准,Chrome/Edge/Safari支持较好,Firefox仅返回空字符串,IE完全不支持。

HTML 原生不支持 直接上传文件夹并自动展示其内部文件列表——必须用 JavaScript 读取 webkitdirectory 或 directory 属性触发的 FileList,再手动渲染 DOM;否则只会显示“1 个文件夹”,不展开内容。
为什么加了 webkitdirectory 还看不到子文件?
浏览器只在用户明确选择**文件夹**(而非文件)时才填充 input.files,且该 FileList 包含的是整个目录树下的所有 File 对象(含路径信息),但默认不递归展开、也不带层级结构。
- 必须监听
change事件,并检查e.target.webkitDirectory是否为true(Chrome/Safari)或用e.target.directory(Firefox 实验性支持) -
input.files是扁平化的FileList,每个File的webkitRelativePath属性才包含完整路径(如"docs/report.pdf"),这是唯一能还原层级的依据 - IE 和旧 Edge 完全不支持,
webkitRelativePath在 Firefox 中返回空字符串(仅 Chrome/Edge 116+ / Safari 16.4+ 可靠) - 不能依赖
File.name推断路径——它只返回纯文件名,无目录信息
怎么安全渲染带路径的文件列表?
直接拼 HTML 显示 webkitRelativePath 有 XSS 风险(路径可能含恶意字符),且需避免重复渲染、DOM 泄漏。关键动作是清洗路径、构造唯一 key、绑定删除逻辑。
- 用
Array.from(input.files)转成真数组,再用.map(f => ({ ...f, path: f.webkitRelativePath || f.name }))提取路径 - 路径清洗:用
path.replace(/[^a-zA-Z0-9._\-/ ]/g, '')剔除控制字符,或用document.createTextNode(path).textContent转义后插入 - 每个列表项必须加
data-index或data-path-hash(如crypto.subtle.digest('SHA-256', new TextEncoder().encode(f.webkitRelativePath))简化版可用f.webkitRelativePath + f.size + f.lastModified) - 不要用
innerHTML = listHtml全量重写——上百文件会卡顿,改用document.createDocumentFragment()批量 append
删除文件夹内某文件时,如何同步更新?
用户点击“删除”按钮,不是删 DOM 就完事——input.files 是只读的,你删的只是自己维护的副本;若不清理,提交时仍会上传已删文件。
- 必须维护一个独立的
let selectedFiles = []数组,每次change后用Array.from(input.files)全量覆盖 - 删除操作按
data-index找到对应项,用selectedFiles.splice(index, 1)移除,并重新生成 DOM 列表 - 禁止用
input.value = ''清空——这在 Chrome 下无效,在 Safari 下会清掉整个选择,但无法恢复已删项的状态 - 页面刷新后状态丢失是必然的,如需持久化,得把
selectedFiles序列化进sessionStorage,并在DOMContentLoaded时重建 DOM(注意:File对象不能存入 storage,只能存路径/大小/时间戳等元数据)
最易被忽略的一点:webkitRelativePath 不是标准属性,不同浏览器行为差异大;如果你的应用必须支持 Firefox 或旧版本 Chrome,就别依赖它做路径展示——改用纯文件名列表 + 显式提示“文件夹上传仅显示文件名”,否则用户会误以为功能异常。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











