2

系列文章

关于前端上传文件全面基础扫盲贴(零)
关于前端上传文件全面基础扫盲贴(一) ----- XMLHttpRequest
关于前端上传文件全面基础扫盲贴(二) ----- File
关于前端上传文件全面基础扫盲贴(三) ----- FormData
关于前端上传文件全面基础扫盲贴(四) ----- FileReader
关于前端上传文件全面基础扫盲贴(五) ----- H5拖拽事件
关于前端上传文件全面基础扫盲贴(六) ----- 图片上传,旋转,重绘,预览等实战(附DEMO)

FileReader对象(知识点主要来源于关于FileReader API)

摘自上面来源,分析的挺好,我又无耻得搬下来了:

使用FileReader对象,web应用程序可以异步的读取存储在用户计算机上的文件(或者原始数据缓冲)内容,可以使用File对象或者Blob对象来指定所要处理的文件或数据.其中File对象可以是来自用户在一个<input>元素上选择文件后返回的FileList对象,也可以来自拖放操作生成的 DataTransfer对象,还可以是来自在一个HTMLCanvasElement上执行mozGetAsFile()方法后的返回结果.

在这里作用就是当你上传图片之后,可以直接从本地先读取出原始数据,然后在页面上展示出来,就是传说中的预览图片功能,在上传到后台前就已经能先拿原始数据来使用了

看看兼容性如何(温馨提示:下图只代表支持程度,支持归支持,不一定百分百支持,所以用到部分方法时不兼容时正常的)
图片描述

创建一个FileReader对象:

var reader = new FileReader();

事件处理程序:

事件 描述
onabort 当读取操作被中止时调用
onerror 当读取操作发生错误时调用
onload 当读取操作成功完成时调用
onloadend 当读取操作完成时调用,不管是成功还是失败.该处理程序在onload或者onerror之后调用
onloadstart 当读取操作将要开始之前调用
onprogress 在读取数据过程中周期性调用
abort 中止该读取操作.在返回时,readyState属性的值为DONE.当该FileReader对象没有在进行读取操作时(也就是readyState属性的值不为LOADING时),调用abort()方法会抛出异常DOM_FILE_ABORT_ERR

下面方法会开始读取指定的Blob对象或File对象中的内容. 当读取操作完成时,readyState属性的值会成为DONE,如果设置了onloadend事件处理程序,则调用之.区别在于:

属性 描述
readAsArrayBuffer result属性中将包含一个ArrayBuffer对象以表示所读取文件的内容
readAsBinaryString result属性中将包含所读取文件的原始二进制数据
readAsDataURL result属性中将包含一个data: URL格式的字符串以表示所读取文件的内容.(这个就是实现我们预览的重要方法了!!!!!)
readAsText result属性中将包含一个字符串以表示所读取的文件内容

介绍到这里就差不多了,接下来看看怎么实现不提交后台实现预览图片,这里只展示这部分功能先

示例

<!doctype html>
<html>

  <head>
    <meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
    <title></title>
    <script type="text/javascript">
      var oFReader = new FileReader();

      oFReader.onload = function (oFREvent) {
        document
          .getElementById("uploadPreview")
          .src = oFREvent.target.result;
      };

      function loadImageFile() {
        if (document.getElementById("uploadImage").files.length === 0) 
          return;
        var oFile = document
          .getElementById("uploadImage")
          .files[0];
        oFReader.readAsDataURL(oFile);
      }
    </script>
  </head>

  <body>
    <form name="uploadForm">
      <img id="uploadPreview"/>
      <input id="uploadImage" type="file" name="myPhoto" onchange="loadImageFile();"/>
    </form>
  </body>

</html>

你看,其实很简单,没什么复杂代码,只是需要的范围比较广,为了一个上传图片已经折腾了多少知识点了,还没完呢...o(一︿一+)o

回归正题,说说几个要点,首先看看代码的
document.getElementById("uploadImage")出现了好几次了,是不是好碍眼?是不是好想优化?是不是想为什么不把他放到一个变量存起来算了?
不行的,因为当你存一个变量之后再上传文件,你就找不到FileReader对象了,详情可以参考一下我之前写的关於Javascript基本类型和引用类型小知识

然后oFReader.onload里面的oFREvent就是你能够拿到的数据了,里面大概长这样子的,看的眼花缭乱,你们可以慢慢挖掘

图片描述
其中:
readyState: 0-还没有加载任何数据.1-数据正在被加载.2-已完成全部的读取请求.
result: 返回文件的内容。只有在读取操作完成后,此属性才有效,返回的数据的格式取决于是使用哪种读取方法来执行读取操作的。

中间插播一则消息吧,图中可看到一个result属性的地址,那是一个base64 编码.就是可以将一副图片数据编码成一串字符串,使用该字符串代替图像地址。
我们所看到的网页上的每一个图片,都是需要消耗一个 http 请求下载而来的,后面因此诞生的精灵图就是基于这个问题才出来,不过局限性比较大,很难适用到所有项目
详情可以参考一下【前端攻略】:玩转图片Base64编码

另外就是兼容问题,因为懒得一个个去验证,就没写上去,不过查过资料放下来给你们,可能有用到,详情可以参考一下
对于 Chrome、Firefox、IE10 使用 FileReader 来实现。
对于 IE6~9 使用滤镜 filter:progid:DXImageTransform.Microsoft.AlphaImageLoader 来实现。

<!doctype html>
<html>

  <head>
    <meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
    <title></title>
    <script type="text/javascript">
      var loadImageFile = (function () {
        if (window.FileReader) {
          var oPreviewImg = null,
            oFReader = new window.FileReader(),
            rFilter = /^(?:image\/bmp|image\/cis\-cod|image\/gif|image\/ief|image\/jpeg|image\/jpeg|image\/jpeg|image\/pipeg|image\/png|image\/svg\+xml|image\/tiff|image\/x\-cmu\-raster|image\/x\-cmx|image\/x\-icon|image\/x\-portable\-anymap|image\/x\-portable\-bitmap|image\/x\-portable\-graymap|image\/x\-portable\-pixmap|image\/x\-rgb|image\/x\-xbitmap|image\/x\-xpixmap|image\/x\-xwindowdump)$/i;

          oFReader.onload = function (oFREvent) {
            if (!oPreviewImg) {
              var newPreview = document.getElementById("imagePreview");
              oPreviewImg = new Image();
              newPreview.appendChild(oPreviewImg);
            }
            oPreviewImg.src = oFREvent.target.result;
          };

          return function () {
            var aFiles = document
              .getElementById("imageInput")
              .files;
            if (aFiles.length === 0) 
              return;
            if (!rFilter.test(aFiles[0].type)) {
              alert("You must select a valid image file!");
              return;
            }
            oFReader.readAsDataURL(aFiles[0]);
          }
        } else if (navigator.appName === "Microsoft Internet Explorer") {
          return function () {
            document
              .getElementById("imagePreview")
              .filters
              .item("DXImageTransform.Microsoft.AlphaImageLoader")
              .src = document
              .getElementById("imageInput")
              .value;
          }
        }
      })();
    </script>
    <style type="text/css">
      #imagePreview {
        filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale);
      }
    </style>
  </head>

  <body>
    <input id="imageInput" type="file" name="myPhoto" onchange="loadImageFile();"/>
    <div id="imagePreview"></div>
  </body>

</html>

没有IE浏览器测试,所以不知道是不是有效,其实里面看起来比我写的那个复杂,实际上多了个检验格式:

rFilter = /^(?:image\/bmp|image\/cis\-cod|image\/gif|image\/ief|image\/jpeg|image\/jpeg|image\/jpeg|image\/pipeg|image\/png|image\/svg\+xml|image\/tiff|image\/x\-cmu\-raster|image\/x\-cmx|image\/x\-icon|image\/x\-portable\-anymap|image\/x\-portable\-bitmap|image\/x\-portable\-graymap|image\/x\-portable\-pixmap|image\/x\-rgb|image\/x\-xbitmap|image\/x\-xpixmap|image\/x\-xwindowdump)$/i;

IE上兼容写法:

document.getElementById("imagePreview").filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = document.getElementById("imageInput").value;

所以不要怕,如果我错了记得提醒下我啊。

目前为止其实已经该说的都差不多覆盖到了吧,动手能力强的话已经可以根据教程写一个实例出来的了。我看情况要不要加一个实战代码做系列结尾。


Afterward
621 声望62 粉丝

努力去做,对的坚持,静待结果