首页 > 技术文章 > 使用URL.createObjectURL()与FileReader API实现文件(图片)上传立即回显

frank-link 2019-11-27 09:40 原文

来自mozilla的定义:

FileReader 对象允许Web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数据。

其中File对象可以是来自用户在一个<input>元素上选择文件后返回的FileList对象,也可以来自拖放操作生成的 DataTransfer对象,还可以是来自在一个HTMLCanvasElement上执行mozGetAsFile()方法后返回结果。

重要提示: FileReader仅用于以安全的方式从用户(远程)系统读取文件内容 它不能用于从文件系统中按路径名简单地读取文件。 要在JavaScript中按路径名读取文件,应使用标准Ajax解决方案进行服务器端文件读取,如果读取跨域,则使用CORS权限。

Note: 此特性在 Web Worker 中可用。
 

URL.createObjectURL() 静态方法会创建一个 DOMString,其中包含一个表示参数中给出的对象的URL。这个 URL 的生命周期和创建它的窗口中的 document 绑定。这个新的URL 对象表示指定的 File 对象或 Blob 对象。

Note: 此特性在 Web Worker 中可用。

注意:此特性在 Service Worker 中不可用,因为它有可能导致内存泄漏。

https://developer.mozilla.org/zh-CN/docs/Web/API/URL/createObjectURL

对比

  createObjectURL FileReader
兼容性 ie10 ie10
执行机制 同步执行 异步执行(宏任务 - 回调方式)
返回值 获取当前文件的一个内存URL 获取一段data:base64的字符串
内存使用 createObjectURL返回一段带hash的url,并且一直存储在内存中,直到document触发了unload事件(例如:document close)或者执行revokeObjectURL来释放。 FileReader.readAsDataURL返回文件的base64字符串,比blob url消耗更多内存,但是在不用的时候会自动从内存中清除(通过垃圾回收机制)
使用场景 使用createObjectURL可以节省性能并更快速,只不过需要在不使用的情况下手动释放内存 如果不太在意设备性能问题,并想获取图片的base64,则推荐使用FileReader.readAsDataURL

用法:

<input type="file" id="fileElem" multiple accept="image/*" style="display:none" onchange="handleFiles(this.files)">
<a href="#" id="fileSelect">Select some files</a> 
<div id="fileList">
  <p>No files selected!</p>
</div>

1、使用URL对象来展示图片

window.URL = window.URL || window.webkitURL;

const fileSelect = document.getElementById("fileSelect"),
      fileElem = document.getElementById("fileElem"),
      fileList = document.getElementById("fileList");

fileSelect.addEventListener("click", function (e) {
  if (fileElem) {
    fileElem.click();
  }
  e.preventDefault(); // prevent navigation to "#"
}, false);

function handleFiles(files) {
  if (!files.length) {
    fileList.innerHTML = "<p>No files selected!</p>";
  } else {
    fileList.innerHTML = "";
    const list = document.createElement("ul");
    fileList.appendChild(list);
    for (let i = 0; i < files.length; i++) {
      const li = document.createElement("li");
      list.appendChild(li);
      
      const img = document.createElement("img");
      img.src = window.URL.createObjectURL(files[i]); // 生成的地址可以看做是本地的一个静态资源地址 blob:https://mdn.mozillademos.org/7de34695-285e-4d1a-aeaf-7fe363ff42e5
      img.height = 60;
      img.onload = function() {
        window.URL.revokeObjectURL(this.src); // 生成的图片地址是一个object URL,即使之前创建了同一张图片的object URL,此时也会重新创建,所以为了优化性能,图片加载完成后,请手动释放该对象
      }
      li.appendChild(img);
      const info = document.createElement("span");
      info.innerHTML = files[i].name + ": " + files[i].size + " bytes";
      li.appendChild(info);
    }
  }
}

2、使用来FileReader 展示图片

function handleFiles(files) {
  for (let i = 0; i < files.length; i++) {
    const file = files[i];
    
    if (!file.type.startsWith('image/')){ continue }
    
    const img = document.createElement("img");
    img.classList.add("obj");
    img.file = file;
    preview.appendChild(img); // Assuming that "preview" is the div output where the content will be displayed.
    
    const reader = new FileReader();
    reader.onload = (function(aImg) { return function(e) { aImg.src = e.target.result; }; })(img);
    reader.readAsDataURL(file);
  }
}

 上述两种方式都可以用来预览图片等其他本地资源,具体可自行尝试。

推荐阅读