Blob & File
Blob 和 File 都是是一个文件对象,File 在 Blob 的基础上进行了功能扩展,两者可以通过 new 实例的方式获取。
1 2
| const blob = new Blob(blobParts, options); const File = new File(fileBits, fileName, options)
|
在参数上,File 多了一个文件名的参数,另外在 options 里还多了一个可选的 lastModified 上次修改时间。

通过打印同一个图片的 Blob 和 File 更嫩直观的看出属性上的差异,另外还可以看到 File 继承了 Blob。
FileReader
读取文件对象的构造函数
1
| const reader = new FileReader()
|
实例上有几个方法
- readAsDataURL(blob): 读取文件对象的内容,将内容用 data:URL 的形式表示,比较常用,例如读取图片文件复制给 img 的 src。
- readAsArrayBuffer(blob):将内容用 ArrayBuffer 的形式表示
- readAsText(blob):将内容用字符串形式表示
- abort(): 终止文件的读取
还有几个事件,也可以理解为读取文件的声明周期
- abort 终止时触发
- error 读取跑出错误触发
- load 读取成功触发
- loadend 读取完成时触发,无论成功还是失败
- loadstart 开始读取时触发
- progress 定期触发
1 2 3 4 5
| const reader = new FileReader(); reader.onload = (res) => { console.log(res); }; reader.readAsDataURL(file);
|

可以看到使用 readAsDataURL 转换出的结果在 onload 事件入参的 target.result 属性
Base64
Base64 是将二进制转化成 ASCII 字符的编码方式
window.atob window.btoa
浏览器提供了两个方法用于 Base64 的编码和解码

URL.createObjectURL
URL 提供了一个静态方法 createObjectURL,通过该方法可以对象创建一个临时的 URL 用来访问,浏览器卸载时会自动释放这个 url,当然还可以通过 revokeObjectURL来手动卸载。
图片预览
1 2 3
| const url = URL.createObjectURL(file); window.open(url); URL.revokeObjectURL(url);
|
通过 createObjectURL 给图片文件创建一个临时 url 然后在浏览器访问地址实现预览
下载
1 2 3 4 5 6
| const url = URL.createObjectURL(file); const a = document.createElement("a"); a.href = url; a.download = "download.png"; a.click(); URL.revokeObjectURL(url);
|
实践
将 DOM 上的 svg 转换成各种格式文件
思路就是先拿到 DOM 节点,然后通过 XMLSerializer 的 serializeToString 方法将 DOM 节点转为 string
然后通过 window.btoa 进行编码,
拼接成 dataURL 的格式,就可以传给 image 的 src 了
通过 image 的加载使用 canvas 画图,借助 toBlob 方法就可以转成 Blob 的格式,Blob 再转换成 File 就非常简单了。
用以下代码需要有一个 svg
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| const svgNode = document.querySelector("svg"); const s = new XMLSerializer().serializeToString(svgNode);
const base64 = window.btoa(s)
const encodedData = `data:image/svg+xml;base64,${base64}`; const img = new Image();
img.onload = function () { const canvas = document.createElement("canvas"); const ctx = canvas.getContext("2d"); canvas.height = img.height; canvas.width = img.width; ctx.drawImage(img, 0, 0); canvas.toBlob((blob) => { const file = new File([blob], "image.png", { type: "image/png" }); console.log(file); const url = URL.createObjectURL(file); const a = document.createElement("a"); a.download = "img.png"; a.href = url; a.click(); }); }; img.src = encodedData;
|
修改上传图片的宽高
这个思路和上个差不多,区别在于拿到的是 File 格式文件,需要先使用 FileReader 读取,然后在 canvas 画图时要使用新的宽高,这样画出来的图才是新的宽高。
用以下代码需要有一个 type 为 file id 为 upload 的 input,一个 id 为 btn 的 button
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| const newWidth = 200; const newHeight = 200; document.querySelector("#btn").addEventListener("click", () => { const file = document.querySelector("#upload").files[0]; const reader = new FileReader(); const img = new Image(); reader.onload = (e) => { img.src = e.target.result; img.onload = () => { const canvas = document.createElement("canvas"); canvas.width = newWidth; canvas.height = newHeight; const ctx = canvas.getContext("2d"); ctx.drawImage(img, 0, 0, newWidth, newHeight); document.body.appendChild(canvas); }; }; reader.readAsDataURL(file); });
|
canvas.drawImage
1 2 3
| drawImage(image, dx, dy) drawImage(image, dx, dy, dWidth, dHeight) drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
|
这个方法参数巨多,一般情况下只传三个就行了,但是遇到上文要修改图片宽高时,或者截取图片的某一部份时,其他参数就有作用了,下图来自MDN 可以很直观的看到各个参数的含义。
