在实际开发过程中,Base64 经常会用于处理图片的预览、上传、下载等。
FileReader.readAsDataURL()
触发loaded
,并在回调中获取到data:URL
convertBase64ImageData()
解析data:URL
,拿到base64Data
contentType
base64ToBlob()
将base64Data
转换为Blob
FormData().append()
可用于上传URL.createObjectURL()
可用于下载
原生 Base64 编码和解码
从 IE10+浏览器开始,所有浏览器就原生提供了 Base64 编码解码方法,不仅可以用于浏览器环境,Service Worker 环境也可以使用。
它们就是 atob
和 btoa
:
a
表示 Base64 字符串b
表示 普通字符串
window.btoa('lovchun.com') // bG92Y2h1bi5jb20=
window.atob('bG92Y2h1bi5jb20=') // lovchun.com
预览图片
-
监听
<input type="file" />
的onchange
拿到选中的File
对象; -
使用
FileReader
的readAsDataURL
并在load
事件中获取到data:URL
格式的字符串(base64 编码); -
将
data:URL
赋值到img.src
即可预览图片;
FileInput.jsx
import React, { useState } from 'react'
import Image from 'next/image'
const FileInput = () => {
const [selectedFile, setSelectedFile] = useState(null)
const onChange = (e) => {
const file = e.target.files[0]
const reader = new FileReader()
if (file) {
reader.readAsDataURL(file)
}
reader.addEventListener(
'load',
() => {
setSelectedFile(reader.result)
},
false
)
}
return (
<form className="flex items-center space-x-6 py-6">
<div className="shrink-0">
{selectedFile && (
<Image
className="h-16 w-16 object-cover"
src={selectedFile}
alt="upload-image"
width={100}
height={100}
/>
)}
</div>
<label className="block">
<input
type="file"
onChange={onChange}
className="block w-full text-sm text-gray-900 file:mr-4
file:rounded-full file:border-0 file:bg-cyan-500
file:py-2 file:px-4
file:text-sm file:font-semibold
file:text-white dark:text-gray-300
dark:file:bg-gray-700 dark:file:text-gray-400
"
/>
</label>
</form>
)
}
export default FileInput
上传图片
从 data:URL 中解析出 base64Data 和 contentType
convertBase64ImageData
/**
* data:image/jpeg;base64,XXXXXX
*
* 解析成
*
* {
* base64Data: 'XXXX',
* contentType: 'image/jpeg'
* }
*/
function convertBase64ImageData(base64Url) {
const arr = base64Url.split(',')
const [metaData, base64Data] = arr
const contentType = metaData.match(/:(.*?);/)[1]
return {
base64Data,
contentType,
}
}
将 base64Data 和 contentType 转换为 Blob
base64ToBlob
function base64ToBlob(base64Data, contentType = '') {
// atob 将 base64 字符串解码为新的字符串
const byteCharacters = atob(base64Data)
// 使用 charCodeAt 将 byteCharacters 中的每个字节添加到 byteNumbers
const byteNumbers = new Array(byteCharacters.length)
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i)
}
// new TypedArray() 创建 ArrayBuffer 的视图
const byteArray = new Uint8Array(byteNumbers)
// 创建 blob
const blob = new Blob([byteArray], {type: contentType})
return blob;
}
使用 FormData.append() 添加 Blob
FileInput.jsx
const onChange = (e) => {
const file = e.target.files[0]
const reader = new FileReader()
if (file) {
reader.readAsDataURL(file)
}
reader.addEventListener(
'load',
() => {
setSelectedFile(reader.result)
+ const {
+ base64Data,
+ contentType
+ } = convertBase64ImageData(reader.result)
+ const blob = base64ToBlob(base64Data, contentType)
+ const formData = new FormData()
+ formData.append('file', blob) // 《== 上传参数
},
false
)
}
下载图片
在某些情况中,我们可能需要使用 JS 去下载 data:URL
的图片,例如:小程序太阳码
小程序太阳码,由微信直接返回 data:URL
字符串,如果需要下载它:
-
data:URL
转换为Blob
; -
URL.createObjectURL
引用Blob
; -
创建
<a />
标签触发点击,完成下载;
downloadBlob
const downloadBlob = (blob, filename) => {
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
// for IE
window.navigator.msSaveOrOpenBlob(blob, filename)
return
}
let downloadLink = document.createElement('a')
let downloadURL = URL.createObjectURL(blob)
downloadLink.href = downloadURL
downloadLink.download = filename
downloadLink.click()
setTimeout(() => {
downloadLink = null
// URL.createObjectURL() 每次调用,都会创建一个新的 URL 对象
// 每个 URL 对象必须调用 revokeObjectURL() 来释放内存
URL.revokeObjectURL(downloadURL)
downloadURL = null
}, 1000)
}
编辑此页
最后更新于47 天之前