如何用原生JS将input图片与其他信息存至localStorage并读取
原生JS实现图片+关联表单信息存储到localStorage的方案
核心逻辑:
FileReader读取生成的 Base64 DataURL 支持直接JSON序列化,可直接存入localStorage;原生File对象本身无法被结构化序列化,不能直接写入存储。
1. 原有图片预览逻辑改造(暂存图片读取结果)
你当前的代码读取完DataURL仅完成了预览赋值,没有暂存图片核心信息,后续组装存储数据时会无法拿到读取结果,需要在作用域内增加临时变量存储图片信息,同时补充文件类型校验:
// 作用域内临时变量,存储当前选中的图片信息 let currentSelectedImage = null; function onFileSelected(event) { const selectedFile = event.target.files[0]; // 校验是否选中图片类型文件 if (!selectedFile.type.startsWith('image/')) { alert('请选择图片类型文件'); event.target.value = ''; return; } const reader = new FileReader(); const imgtag = document.getElementById("food"); imgtag.title = selectedFile.name; reader.onload = function(loadEvent) { const imageDataUrl = loadEvent.target.result; imgtag.src = imageDataUrl; // 暂存图片核心信息,供后续和表单数据组装 currentSelectedImage = { fileName: selectedFile.name, fileSize: selectedFile.size, dataUrl: imageDataUrl }; }; reader.readAsDataURL(selectedFile); }
2. 数组结构存储实现
按照数组结构优先的要求,固定一个专属存储键名,每次写入时先读取本地已有的数组,将本次新增的「图片信息+关联表单字段」对象push到数组末尾,整体序列化后写回localStorage:
// 本地存储的固定键名 const STORAGE_KEY = 'storedFoodRecords'; function saveRecordToLocal(relatedFormData) { // 校验是否已选中图片 if (!currentSelectedImage) { alert('请先选择需要上传的图片'); return; } // 组装单条存储对象:合并图片信息 + 其他关联表单字段 const recordItem = { id: Date.now(), // 生成唯一标识,方便后续读取、删除操作 createTime: new Date().toISOString(), image: currentSelectedImage, // 接收传入的其他表单关联信息,可任意扩展字段 formInfo: relatedFormData }; try { // 读取本地已有的数组,首次使用时初始化为空数组 let storageList = []; const rawStorage = localStorage.getItem(STORAGE_KEY); if (rawStorage) { storageList = JSON.parse(rawStorage); // 兜底校验:如果本地存储被篡改导致非数组,重新初始化 if (!Array.isArray(storageList)) { storageList = []; } } // 新记录push到数组尾部 storageList.push(recordItem); // 整体序列化后写回localStorage localStorage.setItem(STORAGE_KEY, JSON.stringify(storageList)); // 存储完成后重置临时状态,避免重复提交 currentSelectedImage = null; document.querySelector('input[type="file"]').value = ''; document.getElementById('food').src = ''; alert('存储成功'); } catch (err) { // 捕获常见异常:localStorage容量超限、序列化失败等 alert(`存储失败:${err.message}`); } } // 触发存储的示例逻辑 function submitRecord() { // 收集其他关联表单字段,可根据实际业务扩展 const foodName = document.getElementById('foodName').value; saveRecordToLocal({ foodName: foodName }); }
对应补充的HTML结构示例:
<div class="immagine_cibo"> <input type="file" onchange="onFileSelected(event)"> <img id="food" height="200" width="250"> <!-- 补充的关联表单、操作按钮、渲染容器 --> <input type="text" id="foodName" placeholder="输入关联的食物名称"> <button onclick="submitRecord()">提交存储</button> <div id="recordList" style="margin-top: 20px;"></div> </div>
3. 存储内容读取实现
读取时直接通过固定键名拉取本地原始字符串,JSON反序列化后即可拿到完整的数组结构,存储的DataURL可直接赋值给img标签的src属性完成渲染:
function getStoredRecords() { const rawStorage = localStorage.getItem(STORAGE_KEY); if (!rawStorage) return []; try { const storageList = JSON.parse(rawStorage); // 兜底校验返回合法数组 return Array.isArray(storageList) ? storageList : []; } catch (err) { console.error('读取存储失败', err); return []; } } // 读取后渲染到页面的示例 function renderStoredRecords() { const records = getStoredRecords(); const container = document.getElementById('recordList'); container.innerHTML = ''; records.forEach(record => { const itemDom = document.createElement('div'); itemDom.style.border = '1px solid #eee'; itemDom.style.padding = '10px'; itemDom.style.margin = '10px 0'; itemDom.innerHTML = ` <img src="${record.image.dataUrl}" style="height:100px;width:125px;"> <p>文件名:${record.image.fileName}</p> <p>关联信息:${JSON.stringify(record.formInfo)}</p> <p>存储时间:${record.createTime}</p> `; container.appendChild(itemDom); }) } // 页面加载时自动渲染已存储的内容 window.onload = renderStoredRecords;
关键注意事项
- localStorage 单域名通常有5MB左右的容量限制,Base64格式的图片会比原文件体积大33%左右,不适合存储超大尺寸图片,需提前控制单张图片大小
- 写入存储时必须通过
JSON.stringify对数组、对象做序列化,直接存储对象会被自动转成[object Object]的无效字符串 - FileReader为异步执行逻辑,不能在
readAsDataURL调用后立刻读取图片结果,必须在onload回调拿到DataURL后再触发存储操作 - 读取流程必须增加JSON解析的异常兜底,避免本地存储被异常篡改导致页面运行报错
内容的提问来源于stack exchange,提问作者Labarbona Dibaggio
相关产品推荐
相关产品推荐

