如何在单页实现多个自定义文件上传组件并解决选中文件不显示问题
多文件上传组件修复方案
核心问题说明
- 页面内所有上传组件重复使用了相同的id
my-file,label的for属性绑定同一个id,导致label与输入框关联异常 - 给label绑定的click事件添加了
return false,阻止了label默认触发关联输入框选择文件的行为 - JS中
the_return是所有.file-return元素的节点集合,无法直接对整体设置innerHTML,需要定位到当前触发事件的输入框对应的展示元素 - 未添加拖拽相关事件监听,拖拽上传功能无法生效
- 直接取
input.value会显示浏览器默认的伪路径,展示效果差,建议直接取文件名
修复后代码
HTML代码
<div class="upload--input__custom"> <div class="upload--container"> <p>Drop files here or</p> <input class="upload--input" id="my-file1" type="file"> <label tabindex="0" for="my-file1" class="upload--label">Select Files</label> <p class="file-return"></p> </div> </div> <div class="upload--input__custom"> <div class="upload--container"> <p>Drop files here or</p> <input class="upload--input" id="my-file2" type="file"> <label tabindex="0" for="my-file2" class="upload--label">Select Files</label> <p class="file-return"></p> </div> </div>
JS代码
var fileInput = document.querySelectorAll(".upload--input"), button = document.querySelectorAll(".upload--label"), containers = document.querySelectorAll(".upload--container"); for (let i = 0; i < button.length; i++) { button[i].addEventListener("keydown", function(event) { if (event.keyCode == 13 || event.keyCode == 32) { this.previousElementSibling.click(); } }); } // 移除阻止默认行为的return false,保留聚焦逻辑即可 for (let i = 0; i < button.length; i++) { button[i].addEventListener("click", function(event) { this.previousElementSibling.focus(); }); } for (let i = 0; i < fileInput.length; i++) { fileInput[i].addEventListener("change", function(event) { // 找到当前输入框对应的file-return元素 const currentReturn = this.parentElement.querySelector('.file-return'); // 优先取文件名展示 currentReturn.innerHTML = this.files.length ? this.files[0].name : this.value; }); } // 添加拖拽功能 for (let i = 0; i < containers.length; i++) { // 阻止拖拽默认行为 containers[i].addEventListener('dragenter', (e) => e.preventDefault()); containers[i].addEventListener('dragover', (e) => e.preventDefault()); containers[i].addEventListener('drop', function(e) { e.preventDefault(); const currentInput = this.querySelector('.upload--input'); const currentReturn = this.querySelector('.file-return'); // 赋值拖拽的文件到输入框 currentInput.files = e.dataTransfer.files; // 展示文件名 currentReturn.innerHTML = currentInput.files.length ? currentInput.files[0].name : ''; }) }
CSS代码
CSS部分无需修改,可直接沿用原有代码:
.upload--input__custom{ border: 1px dashed black; height: 200px; width: 100%; display: flex; align-items: center; justify-content: center; flex-direction: column; border-radius: 10px; -webkit-border-radius: 10px; -moz-border-radius: 10px; -ms-border-radius: 10px; -o-border-radius: 10px; } .upload--container { position: relative; width: 100%; margin: 0 auto; text-align: center; height: 100%; display: flex; align-items: center; justify-content: center; flex-direction: column; } .upload--container p{ color: blue; margin-bottom: .75rem; font-size: 17px; } .upload--label { width: fit-content !important; display: block; padding: 12px 20px; background: yellow; color: #fff !important; font-size: 1em; transition: all 0.4s; cursor: pointer; -webkit-transition: all 0.4s; -moz-transition: all 0.4s; -ms-transition: all 0.4s; -o-transition: all 0.4s; } .upload--label::after{ content: unset !important; } .upload--input { opacity:0; width: 100% !important; height: 100%; padding: 14px 0; cursor: pointer; width: fit-content; position: absolute; left:0; top: 0; z-index: 1000; } .file-return { margin: 0; width: 70%; height: 30px; background-color: burlywood; } .file-return:not(:empty) { margin: 1em 0; text-align: center; } .file-return { font-style: italic; font-size: 0.9em; font-weight: bold; } .file-return:not(:empty):before { content: "Selected file: "; font-style: normal; font-weight: normal; }
内容的提问来源于stack exchange,提问作者h.m.p.frontendDeveloper
相关产品推荐
相关产品推荐

