如何使用 JavaScript 将图片转换为字符串并保存到 localStorage?
可以用 FileReader.readAsDataURL() 将用户选择的图片转换成 Data URL 字符串,再用 localStorage.setItem() 保存。页面重新加载时,读取这个字符串并赋给头像元素的 src,就能恢复头像。
这种方式适合保存体积较小的头像。转换和保存都在浏览器本地完成,不会自动上传图片。
为什么刷新后头像会消失?
如果更换头像时只修改了 <img> 的 src,这些修改不会自动保留。刷新页面后,浏览器会重新执行页面代码。
localStorage 的键和值都是字符串,不能直接保存 File 或 Blob 中的图片数据。Data URL 可以将图片内容编码为字符串,例如:
data:image/png;base64,iVBORw0KGgo...
其中,image/png 表示图片类型,base64 后面是编码后的图片内容。完整字符串可以直接赋给 <img> 的 src,无需再用 JSON.stringify() 处理。
实现步骤
- 使用
<input type="file">让用户选择图片。 - 调用
FileReader.readAsDataURL(file),等待读取完成。 - 将得到的字符串存入
localStorage,并更新头像。 - 页面加载时,读取保存的字符串并恢复头像。
FileReader 以异步方式读取文件,调用 readAsDataURL() 后需要等待 load 事件,才能获取结果。
完整代码示例
将下面的代码保存为 HTML 文件,通过本地 HTTP 服务打开即可。示例将头像文件大小限制为 1 MiB,这只是演示中的限制,不代表 localStorage 的容量上限。
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>保存个人头像</title>
</head>
<body>
<img
id="avatar"
alt="个人头像"
width="120"
height="120"
style="object-fit: cover; border-radius: 50%;"
hidden
>
<p>
<label for="avatar-input">选择头像:</label>
<input
id="avatar-input"
type="file"
accept="image/jpeg,image/png,image/webp"
>
</p>
<p id="message" role="status">尚未选择头像。</p>
<script>
const STORAGE_KEY = "profile-avatar";
const MAX_FILE_SIZE = 1024 * 1024; // 示例限制:1 MiB
const ALLOWED_TYPES = ["image/jpeg", "image/png", "image/webp"];
const avatar = document.getElementById("avatar");
const input = document.getElementById("avatar-input");
const message = document.getElementById("message");
function showAvatar(dataURL) {
avatar.src = dataURL;
avatar.hidden = false;
}
function readAsDataURL(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.onerror = () => reject(reader.error);
reader.readAsDataURL(file);
});
}
// 页面加载时恢复头像。
try {
const savedAvatar = localStorage.getItem(STORAGE_KEY);
if (savedAvatar) {
showAvatar(savedAvatar);
message.textContent = "已恢复保存的头像。";
}
} catch (error) {
message.textContent = "无法读取本地存储,请检查浏览器设置。";
console.error(error);
}
input.addEventListener("change", async () => {
const file = input.files[0];
if (!file) return;
if (!ALLOWED_TYPES.includes(file.type)) {
message.textContent = "请选择 JPEG、PNG 或 WebP 图片。";
input.value = "";
return;
}
if (file.size > MAX_FILE_SIZE) {
message.textContent = "图片不能超过 1 MiB,请先缩小或压缩图片。";
input.value = "";
return;
}
input.disabled = true;
message.textContent = "正在保存头像……";
try {
const dataURL = await readAsDataURL(file);
// 保存成功后再更新页面,避免显示为已保存却无法恢复。
localStorage.setItem(STORAGE_KEY, dataURL);
showAvatar(dataURL);
message.textContent = "头像已保存,刷新页面后会自动恢复。";
} catch (error) {
message.textContent =
"头像读取或保存失败,可能是图片无法读取、存储空间不足或浏览器限制。";
console.error(error);
} finally {
input.disabled = false;
input.value = "";
}
});
</script>
</body>
</html>
代码中的 accept 用来提示文件选择器允许选择的文件类型,file.type 用于基础检查。两者都不能保证文件内容是有效图片。如果需要严格验证,还应检查图片能否正常解码。
保存时需要注意什么?
不要把 blob: URL 当作持久存储
URL.createObjectURL(file) 常用于预览用户选择的图片,生成的地址通常以 blob: 开头。
这个地址只是浏览器对内存中数据的临时引用。将地址字符串写入 localStorage 并没有保存图片本身,因此不能依靠它在刷新后恢复头像。
readAsDataURL() 返回的字符串包含图片数据,可以用于保存和恢复头像。
图片过大时可能保存失败
Base64 编码后的数据量通常比原始二进制数据增加约三分之一,Data URL 还包含类型等前缀。实际占用多少存储配额,取决于浏览器的计算方式。
localStorage 容量有限,写入时可能抛出 QuotaExceededError 等异常,需要用 try...catch 处理。头像较大时,可以先用 Canvas 缩小尺寸、重新编码,再保存。如果需要存储较多图片,可以考虑使用支持保存 Blob 的 IndexedDB。
本地保存的使用限制
只要浏览器允许存储,且数据未被清除,localStorage 就能在页面刷新和浏览器会话结束后保留数据。它受同源限制,协议、主机名或端口发生变化时,都可能访问到另一份存储。
本地保存的头像不会自动同步到其他设备。用户清除站点数据后,头像会丢失;隐私浏览模式下的数据通常会在会话结束后清除。直接通过 file:// 打开页面时,存储行为可能因浏览器而异,建议通过 HTTP 服务验证。
如果头像属于用户账户,且需要跨设备使用,应将图片上传到服务器或对象存储,并在用户资料中保存可持久访问的图片地址。
备注:内容仅供参考。
