如何优雅的处理前端开发中的File

42次阅读

共计 3632 个字符,预计需要花费 10 分钟才能阅读完成。

本文首发于公众号:符合预期的 CoyPan

写在前面

在前端开发中,我们经常会遇到对文件的操作,特别是对图片的操作。在 Node 端,提供了 file 相关的接口,供我们使用。在浏览器中,Html5 提供了 File 相关的 Web Api。

本文将小小总结一下如何使用 File 相关的 api 来操作文件以及相关的一些知识。

File 对象

一个 File 对象包含了以下的属性:

lastModified: 只读。文件最后修改时间 (UNIX 时间戳)。name: 只读。文件名(不包含完整路径)。size: 只读。文件大小。type: 只读。MIME TYPE。

看一个例子:

在浏览器中,我们也可以直接使用 File 构造函数来构造一个文件对象实例。

var json = `{"a": 1}`;
var f = new File([json], 'test.json', {type: 'application/json'});
console.log(f);

一个 File 对象的内容可以是很多数据类型,包括:ArrayBuffer、ArrayBufferView、Blob、DOMString(在 JS 中,DOMString 就是 String)。本文不做进一步详细介绍。

如何获取一个 File 对象

那么,如何获取一个文件对象呢?上面提到了,我们可以直接使用 File 构造函数。大多数的情况下,我们是需要让用户进行选择,这个时候,就需要用到 input 标签了。代码也很简单,我们只需要把 input 标签的 type 设置为 file 就行。

<html>
    <input type='file'/>
    <script>
        const el = document.querySelector('input');
        el.addEventListener('change', e=> {
            const fileList = e.target.files;
            [].slice.call(fileList).forEach(file => {console.log(file);
            });
        });
    </script>
</html>

我们只需要监听 input 标签的 change 事件,就可以拿到文件对象了。这里需要注意的时候,我们拿到的其实是一个文件列表,而这个文件列表是一个类数组对象,需要转换为数组,才能完全像数组一样遍历。

如果想选择多个文件,则需要在 input 标签上增加 multiple 属性。如果只接受某些类型的文件,可以添加 accept 属性。

 <!-- 可以多选文件 -->
<input type='file' multiple />

<!-- 多选,只能选择图片文件 -->
<input type='file' multiple accept='image/*'/>

上面的图中我们可以看到,直接使用 input 标签是不太美观的。我们可以将 input 标签隐藏,使用代码触发 input 标签的点击事件,就可以达到效果。

<html>
    <input type='file' style="display:none"/>
    <button> 这是一个帅气的按钮 </button>
    <script>
        const inputEl = document.querySelector('input');
        inputEl.addEventListener('change', e => {
            const fileList = e.target.files;
            [].slice.call(fileList).forEach(file => {console.log(file);
            });
        });   
        const btnEl = document.querySelector('button');
          btnEl.addEventListener('click', () => {inputEl.click();
        });
    </script>
</html>

如何读取 File 对象的内容

上面讲了如何拿到一个文件对象,那么怎么读取文件的内容呢?这个时候,就需要用到另外一个 Web Api 了:FileReader

使用 FileReader 读取文件内容,主要步骤为:

// 1、声明一个 FileReader 对象实例
var fileReader = new FileReader();

// 2、监听读取完成事件
fileReader.onload = function(e) {const result = e.target.result;}

// 3、读取文件内容
// 这里的 file 为文件对象。fileReader.readAsDataURL(file); // 以 base64 的方式读取

// fileReader.readAsArrayBuffer() 以 ArrayBuffer 的方式读取
// fileReader.readAsText() 以字符串的方式读取 

一个很常见的场景:读取本地图片,并展示缩略图。实现起来十分简单。

<html>
    <input type='file' accept='image/*' />
    <script>
        const el = document.querySelector('input');
        el.addEventListener('change', e=> {const imgFile = e.target.files[0];
            const reader = new FileReader();
            reader.onload = function(e) {
                const base64 = e.target.result;
                const imgEl = new Image();
                imgEl.src = base64;
                imgEl.onload = function() {document.body.appendChild(imgEl);
                }
            }
            reader.readAsDataURL(imgFile);
        });
    </script>
</html>

想要在浏览器中预览文件,还有另外一种方法:使用 window.URL.createObjectURL

window.URL.createObjectURL 可以接受一个文件对象作为参数,返回一个字符串。这个字符串是一个包含了一个对象 URL,可用于指定源文件对象的内容。看下面的例子:

<html>
    <input type='file' accept='image/*' />
    <script>
        const el = document.querySelector('input');
        el.addEventListener('change', e=> {const imgFile = e.target.files[0];
            const imgSrc = window.URL.createObjectURL(imgFile);
            console.log(imgSrc);
            const imgEl = new Image();
            imgEl.src = imgSrc;
            imgEl.onload = function() {document.body.appendChild(imgEl);
                window.URL.revokeObjectURL(imgFile);
            }
        });
    </script>
</html>

可以看到,这里图片的 src,是一个以 blob: 开头 的字符串。这是浏览器自己实现的一个协议,表示对一个资源的引用,需要挂载到网页中的资源对象上(比如 img,video),才能展示出来。

如何从页面上下载一个自定义的 File

下面的场景是比较常见的:在页面上生成一个自定义文件,然后下载下来。要实现这个需求,可以按照下面的思路:

  1. 首先生成一个文件。这个在前文有讲到,我们可以直接使用 new File 来构造一个文件即可。
  2. 生成一个对该文件的引用。可以使用 window.URL.createObjectURL 来创建对文件的引用。
  3. 下载。使用 a 标签,设置 download 属性。

代码示例:

<html>
    <button> 点击下载 </button>
    <script>
        const btnEl = document.querySelector('button');
        btnEl.addEventListener('click', function() {const json = `{ "a": 1}`;
            const file = new File([json], 'test.json', {type: 'application/json'});
            const url = window.URL.createObjectURL(file);
            const aTag = document.createElement('a');
            aTag.href = url;
            aTag.download = 'test.json';
            aTag.click();});
    </script>
</html>

写在后面

本文主要介绍了在前端页面中,如何处理 File。其实 File 对象是继承自 Blob 对象,File 是特殊的 Blob。Blob 是 Binary Large Object 的缩写,表示一个不可变、原始数据的类文件对象,主要用于处理二进制的数据。关于这一部分的内容,可以移步这篇文章.

另外,最新版的 Chrome 已经支持直接读写本地文件了。点我

正文完
 0