说在前面
💻作为一名前端开发,我们平时也少不了对文件流数据进行处理,今天简单整理一下日常开发中比较常见的一些处理文件流的场景及处理方法,希望可以帮助到大家,挤出多一点的
摸鱼学习时间。
常见场景
一、input框上传文件
带有 type="file"
的 <input>
元素允许用户可以从他们的设备中选择一个或多个文件。选择后,这些文件可以使用提交表单的方式上传到服务器上,或者通过 Javascript 代码和文件 API 对文件进行操作。
如下代码:
<input type="file" id="fileInput" /><script>const input = document.getElementById("fileInput");input.onchange = (e) => {const file = e.target.files[0];console.log(file);};
</script>
如上图,通过inpu框选择文件上传之后,我们可以获取到我们上传的文件对象,那么我们应该怎样将获取到的文件对象更好的展示出来呢?
1、选择图片文件并在页面上显示
这种情况我们可以将获取到的文件对象转换为base64字符,再将其赋予img标签的src属性即可,这里我们需要使用到FileReader
对象来进行读取。
FileReader
对象允许 Web 应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用File
或Blob
对象指定要读取的文件或数据。其中 File 对象可以是来自用户在一个
<input>
元素上选择文件后返回的FileList
对象,也可以来自拖放操作生成的DataTransfer
对象,还可以是来自在一个HTMLCanvasElement
上执行mozGetAsFile()
方法后返回结果。
详细的介绍和更多的使用文档都可以上MDN进行查看,这里我也就不过多赘述了。
想要获取文件的base64 编码,我们可以使用readAsDataURL
方法来读取:
readAsDataURL
方法会读取指定的Blob
或File
对象。读取操作完成的时候,readyState
会变成已完成DONE
,并触发loadend
事件,同时result
属性将包含一个data:
URL 格式的字符串(base64 编码)以表示所读取文件的内容。
具体代码如下:
<input type="file" id="fileInput" />
<img alt="" id="uploadImg" src="" style="width: 100px; height: 100px" />
<div id="uploadText"></div>
<script>const input = document.getElementById("fileInput");input.onchange = (e) => {const file = e.target.files[0];const type = file.type.split("/")[0];console.log("type", type);switch (type) {case "image":dealImg(file);break;};function dealImg(file) {fileToBase64(file).then((base64String) => {console.log("Base64:", base64String);const uploadImg = document.getElementById("uploadImg");uploadImg.setAttribute("src", base64String);}).catch((error) => {console.error("Error:", error);});}function fileToBase64(file) {return new Promise((resolve, reject) => {const reader = new FileReader();reader.onload = () => {resolve(reader.result);};reader.onerror = (error) => {reject(error);};reader.readAsDataURL(file);});}
</script>
2、选择text文本文件并在页面上显示文件内容
首先我们先创建一个txt文件,并写入一些内容:
想要获取文件的文本内容,我们可以使用readAsText
方法来读取:
readAsText
方法可以将 Blob 或者 File 对象转根据特殊的编码格式转化为内容 (字符串形式)
具体代码如下:
<input type="file" id="fileInput" />
<img alt="" id="uploadImg" src="" style="width: 100px; height: 100px" />
<div id="uploadText"></div>
<script>const input = document.getElementById("fileInput");input.onchange = (e) => {const file = e.target.files[0];const type = file.type.split("/")[0];console.log("type", type);switch (type) {case "text":dealText(file);break;}};function dealText(file) {readFile(file).then((text) => {const uploadText = document.getElementById("uploadText");uploadText.innerHTML = text;}).catch((error) => {console.error("Error:", error);});}function readFile(file) {return new Promise((resolve, reject) => {const reader = new FileReader();reader.onload = (event) => {resolve(event.target.result);};reader.onerror = (event) => {reject(error);};reader.readAsText(file); // 使用readAsText方法读取文件内容});}
</script>
二、将img标签图片转换为DataURL数据类型或Blob数据类型
1、将图片转换为 DataUR 数据类型
我们首先获取到 img 标签元素。然后创建一个 canvas 元素,并获取其 2D 上下文。根据图像的宽度和高度设置 canvas 的宽度和高度。接着使用 drawImage
方法将 img 元素中的图像绘制到 canvas 上。最后,使用 toDataURL
方法即可将 canvas 中的内容转换为 DataURL 数据类型,具体代码如下:
function imgToDataUrl() {const imgElement = document.getElementById("uploadImg"); // 获取 img 标签元素const canvas = document.createElement("canvas");const context = canvas.getContext("2d");canvas.width = imgElement.width;canvas.height = imgElement.height;// 在画布上绘制图片context.drawImage(imgElement, 0, 0);// 将画布内容转换为 DataURLconst dataUrl = canvas.toDataURL("image/png");console.log(dataUrl); // 输出 DataURL 数据}
2、将图片转换为 Blob 数据类型
前面canvas绘制图片的步骤是一样的,只是这里最后使用了canvas的toBlob
方法来进行转换,需要注意的是toBlob
方法中的几个参数:
toBlob(callback, type, quality)
callback
回调函数,可获得一个单独的 Blob
对象参数。如果图像未被成功创建,可能会获得 null
值。
type
可选
DOMString
类型,指定图片格式,默认格式(未指定或不支持)为 image/png
。
quality
可选
Number
类型,值在 0 与 1 之间,当请求图片格式为 image/jpeg
或者 image/webp
时用来指定图片展示质量。如果这个参数的值不在指定类型与范围之内,则使用默认值,其余参数将被忽略。
function imgToBlob() {const imgElement = document.getElementById("uploadImg"); // 获取 img 标签元素const canvas = document.createElement("canvas");const context = canvas.getContext("2d");canvas.width = imgElement.width;canvas.height = imgElement.height;// 在画布上绘制图片context.drawImage(imgElement, 0, 0);// 将画布内容转换为 Blobcanvas.toBlob(function (blob) {// 处理获取到的 Blob 数据console.log(blob);}, "image/png");}
获取到的Blob 数据如下:
三、图片压缩
我们可以使用JavaScrip对图片进行质量压缩来缩小图片大小,具体使用到的方法是上面提到的toBlob(callback, type, quality)
,我们可以通过其第三个参数来对质量进行压缩。
function doCompress() {imgToBlob((blob) => {console.log("原图片", blob);compressImage(blob, Infinity, Infinity, 0.9).then((res) => {console.log("压缩质量为0.9得到图片", res);});});}function compressImage(file, maxWidth, maxHeight, quality) {return new Promise((resolve, reject) => {const reader = new FileReader();reader.readAsDataURL(file);reader.onload = function (event) {const img = new Image();img.src = event.target.result;img.onload = function () {let width = img.width;let height = img.height;if (width > maxWidth || height > maxHeight) {const ratio = Math.max(width / maxWidth, height / maxHeight);width /= ratio;height /= ratio;}const canvas = document.createElement("canvas");canvas.width = width;canvas.height = height;const ctx = canvas.getContext("2d");ctx.drawImage(img, 0, 0, width, height);canvas.toBlob(function (blob) {resolve(blob);},"image/jpeg",quality);};};reader.onerror = function (error) {reject(error);};});}function imgToBlob(cb) {const imgElement = document.getElementById("uploadImg"); // 获取 img 标签元素const canvas = document.createElement("canvas");const context = canvas.getContext("2d");canvas.width = imgElement.width;canvas.height = imgElement.height;// 在画布上绘制图片context.drawImage(imgElement, 0, 0);// 将画布内容转换为 Blobcanvas.toBlob(function (blob) {// 处理获取到的 Blob 数据cb(blob);}, "image/png");}
上面代码定义了一个名为compressImage
的函数,它接受四个参数:file
(要压缩的文件),maxWidth
(最大宽度),maxHeight
(最大高度)和quality
(图像质量,范围从0到1)。
在函数内部,我们首先使用FileReader
读取文件,并将其转换为Data URL。然后,我们创建一个Image
对象并将Data URL赋给它。在图像加载完成后,我们根据指定的最大宽度和高度来调整图像大小。
接下来,我们使用<canvas>
元素创建一个画布,并设置其宽度和高度。然后,我们在画布上通过drawImage
方法绘制图像,将其缩放到适当的大小。
最后,我们使用toBlob
方法将画布内容转换为Blob对象,并将其以指定的JPEG格式和质量解析。最终返回压缩后的Blob对象。
具体效果如下:
四、图片加水印
这个之前有单独写了一篇文章,感兴趣的同学可以到这里《javaScript 给图片加水印》查看。
公众号
https://mp.weixin.qq.com/s/psp6iky3YYDl8chs-1nq-A
关注公众号『前端也能这么有趣
』,获取更多新鲜内容。
说在后面
🎉 这里是 JYeontu,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打羽毛球 🏸 ,平时也喜欢写些东西,既为自己记录 📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解 🙇,写错的地方望指出,定会认真改进 😊,偶尔也会在自己的公众号『前端也能这么有趣』发一些比较有趣的文章,有兴趣的也可以关注下。在此谢谢大家的支持,我们下文再见 🙌。