如何基于表单多类型输入(含文件上传)构建指定结构的多维JSON对象
问题原因
- FileReader为异步API,原有代码未等待文件读取完成就直接序列化输出,无法拿到完整的文件数据
- 数据组装逻辑错误,将普通表单字段与文件数据拆分到了不同对象中,未按需求整合为同一结构
- 多文件读取逻辑存在错误,循环中仅读取了第一个选中的文件,未遍历所有选中文件
修复后完整代码
JS代码
var button = $("button"); var divId = $('#myForm'); button.on("click", () => { // 初始化目标结构对象 const result = { files: [] }; // 收集普通表单字段 divId.find('input').each(function() { const $this = $(this); const fieldType = $this.prop('type'); const fieldName = $this.attr('name'); if (fieldType === "checkbox" || fieldType === "radio") { result[fieldName] = $this.is(':checked'); } else if (fieldType !== "button" && fieldType !== "file") { result[fieldName] = $this.val(); } }); // 处理文件读取 const fileDom = divId.find('input[type="file"]')[0]; const selectedFiles = fileDom.files; const totalFileCount = selectedFiles.length; // 无选中文件直接输出结果 if (totalFileCount === 0) { console.log(result); alert(JSON.stringify(result)); return; } // 等待所有文件异步读取完成后再输出 let loadedFileCount = 0; for (let i = 0; i < totalFileCount; i++) { readTheFile(selectedFiles[i], (fileInfo) => { result.files.push(fileInfo); loadedFileCount++; if (loadedFileCount === totalFileCount) { console.log(result); // ArrayBuffer无法直接序列化,此处序列化时做了占位处理,实际使用可按需转base64 alert(JSON.stringify(result, (key, value) => { if (key === 'data' && value instanceof ArrayBuffer) { return '[object ArrayBuffer]'; } return value; })); } }); } }); function readTheFile(file, callback) { const fileReader = new FileReader(); fileReader.filename = file.name; fileReader.onload = function(e) { callback({ FileName: e.target.filename, data: e.target.result }); }; fileReader.readAsArrayBuffer(file); }
HTML代码
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div id="myForm"> <input id="file-attach" type="file" name="uploadFile[]" multiple="multiple" /> <br><br> <input type='text' name='firstName' id='firstName' /> <br><br> <input type='text' name='lastName' id='lastName' /> <br><br> <button>Submit</button> </div>
补充说明
- ArrayBuffer属于二进制数据类型,无法直接被JSON序列化,如果需要将结果转为可传输的JSON字符串,可将文件读取逻辑改为
readAsDataURL直接获取Base64格式的文件内容,也可以使用FormData对象直接提交二进制数据。
内容的提问来源于stack exchange,提问作者Developer
相关产品推荐
相关产品推荐

