zoukankan      html  css  js  c++  java
  • 文件上传_HTML5与SWFUpload(1)

    要实现文件上传,要兼顾IE6份额还不小的市场情况,除了fashion的HTML5,SWFUpload还得用作降级方案。

    Nicholas有一个系列关于利用HTML5上传文件的博客“Working with files in JavaScript”,另外,这里还有一篇也很详细的利用HTML5上传文件的文章(中文版哦)http://www.html5rocks.com/zh/tutorials/file/dndfiles/#toc-slicing-files

    一、利用HTML5进行文件上传(来自Nicholas)

    1、上传文件,可以点击按钮选择文件上传;也可以拖拽上传

    插曲:

    --------------------------------------------------------------------------------------------------------------------------------------

    有一些小问题<input type="file"  />在各种浏览器中的显示都不一样,

    chrome:

    鼠标放到按钮“选择文件”上,就会出现“未选择文件”的tips,这是chrome的特色

    ff:

    opera:

     所以需要统一下样式,简单的处理方式,就是opacity:0(隐藏掉),用单独的a元素做个按钮代替(只是样式上的代替),然后再定位。

    -----------------------------------------------------------------------------------------------------------------------------------------------------------------

    (1)点击按钮选择文件上传

    
    
     1 <input type="file" id="your-files" multiple>//multiple代表可以多文件上传
     2 <script>
     3 var control = document.getElementById("your-files");
     4 control.addEventListener("change", function(event) {
     5 
     6     var i = 0,
     7         files = control.files,
     8         len = files.length;
     9 
    10     for (; i < len; i++) {
    11         console.log("Filename: " + files[i].name);//每个文件名
    12         console.log("Type: " + files[i].type);//每个文件类型
    13         console.log("Size: " + files[i].size + " bytes");//每个文件大小
    14     }
    15 
    16 }, false);
    17 </script>
    
    

     (2)拖拽上传

     1 <div id="your-files">上传文件拖拽到这里</div>
     2 <script>
     3 var target = document.getElementById("your-files");
     4 
     5 target.addEventListener("dragover", function(event) {
     6     event.preventDefault();
     7 }, false);
     8 
     9 target.addEventListener("drop", function(event) {
    10 
    11     event.preventDefault();//取消默认的行为
    12 
    13     var i = 0,
    14         files = event.dataTransfer.files,
    15         len = files.length;
    16 
    17     for (; i < len; i++) {
    18         console.log("Filename: " + files[i].name);
    19         console.log("Type: " + files[i].type);
    20         console.log("Size: " + files[i].size + " bytes");
    21     }
    22 
    23 }, false);
    24 </script>

    2、上传到浏览器的文件,可以利用ajax方式上传到服务器

    通过FormData对象(在XMLHttpRequest Level 2中定义)可以用 Ajax方式对文件上传。该对象代替了HTML的form表单,允许你通过append()方法增加key-value的形式对上传到服务器。

     1 var form = new FormData();
     2 //增加的标识
     3 form.append("name", "Nicholas");
     4 form.append("photo", control.files[0]);
     5 
     6 // 通过XHR上传 - 没有设头信息哦!
     7 var xhr = new XMLHttpRequest();
     8 xhr.onload = function() {
     9     console.log("Upload complete.");
    10 };
    11 xhr.open("post", "/entrypoint", true);
    12 xhr.send(form);

    发post请求的效果,其中可以看到加的name与photo, 至于其中filename乱码的问题,还不知道是编码的原因呢?(页面用的UTF-8)还是什么?

    3、读取文件

    在客户端我们就可以通过FileReader来读取文件内容。

    有四种读文件的方式:

    (1)readAsText()---用text的方式返回文件(txt文件格式,读取没问题,但是doc这类有自己格式的文件,出来就会是乱码)

    (2)readAsBinaryString()---以二进制编码的方式返回文件(已过时了,现在用readAsArrayBuffer)

    (3)readAsArrayBuffer()---用一个ArrayBuffer返回文件内容(对二进制文件很有用,比如图片)

    (4)readAsDataURL()---用data URL 返回文件内容

    所有的这些方法启动读取文件,都类似于XHR对象的send方法启动一个HTTP请求。所以需要在开始读取文件之前监听load事件。

     1 var reader = new FileReader();
     2 reader.onload = function(event) {
     3     var contents = event.target.result;
     4     //输出文件的内容
     5     console.log("File contents: " + contents);
     6 };
     7 
     8 reader.onerror = function(event) {
     9     console.error("File could not be read! Code " + event.target.error.code);
    10 };
    11 
    12 reader.readAsText(file);

    下面用读取URI的方式来读取图片,并利用canvas,设置它的src属性,使得图片在浏览器中呈现出来:

    <canvas id="mycanvas">这里会显示上传的照片</canvas>
    <script>

    var
    reader = new FileReader(); reader.onload = function(event) { var dataUri = event.target.result, context = document.getElementById("mycanvas").getContext("2d"), img = new Image(); // 等到图片被完全加载 img.onload = function() { context.drawImage(img, 100, 100); }; img.src = dataUri; }; reader.onerror = function(event) { console.error("File could not be read! Code " + event.target.error.code); }; reader.readAsDataURL(file);//这里的file可以利用上面提到的上传文件的方式得到,比如前面的control.files[0](单个文件)

    </script>

    4、获取上传文件的进度

    在FileReader过程中有5个事件:

    (1)loadstart--表示加载数据开始。这个事件总是在最开始执行

    (2)progress--当数据在加载过程中时触发,使得能够访问中间的数据

    (3)error--当加载失败时触发

    (4)abort---当数据加载过程被取消时触发(在XMLHttpRequest和FileReader中都能用)

    (5)load---当所有的数据都成功读取以后触发

    (6)loadend---当对象已经完成传输数据以后触发,总是在error,abort和load之后触发

    error和load在 3、读取文件的例子中已经运用了。

    在文件上传过程中,获取文件的进度信息:

    (1)lengthComputable---布尔值,指示浏览器能否决定数据完整的大小

    (2)loaded---已经读取的文件bytes值

    (3)total---需要读取的文件的bytes值

    例子如下:

     1 var reader = new FileReader(),
     2      progressNode = document.getElementById("my-progress");
     3 
     4 reader.onprogress = function(event) {
     5     if (event.lengthComputable) {
     6         progressNode.max = event.total;//精度的最大值
     7         progressNode.value = event.loaded;//进度值
     8     }
     9 };
    10 
    11 reader.onloadend = function(event) {
    12     var contents = event.target.result,
    13         error    = event.target.error;
    14 
    15     if (error != null) {
    16         console.error("File could not be read! Code " + error.code);
    17     } else {
    18         progressNode.max = 1;
    19         progressNode.value = 1;
    20         console.log("Contents: " + contents);
    21     }
    22 };
    23 
    24 reader.readAsText(file);

    根据loaded的进度值,就可以设置元素的背景色等,得到常见的进度条的模样。

    5、处理文件错误信息

    就算是上传本地文件,也会有出错的情况,在File API的说明中,定义了四种类型的文件错误。当在文件读取中发生错误时,FileReader对象错误属性将会指示四种类型错误中的一种。在实际中,浏览器用 FileError对象实现这些文件错误属性:

    (1)FileError.NOT_FOUND_ERR 文件没有找到

    (2)FileError.SECURITY_ERR  安全问题

    (3)FileError.NOT_READABLE_ERR 不可读错误

    (4)FileError.ENCODING_ERR 编码错误

    (5)FileError.ABORT_ERR 当在过程中没有文件读取时,调用abort()

     1 var reader = new FileReader();
     2 
     3 reader.onloadend = function(event) {
     4     var contents = event.target.result,
     5         error    = event.target.error;
     6 
     7     if (error !== null) {
     8         switch (error.code) {
     9             case error.ENCODING_ERR:
    10                 console.error("Encoding error!");
    11                 break;
    12 
    13             case error.NOT_FOUND_ERR:
    14                 console.error("File not found!");
    15                 break;
    16 
    17             case error.NOT_READABLE_ERR:
    18                 console.error("File could not be read!");
    19                 break;
    20 
    21             case error.SECURITY_ERR:
    22                 console.error("Security issue with file!");
    23                 break;
    24 
    25             default:
    26                 console.error("I have no idea what's wrong!");
    27         }
    28     } else {
    29         progressNode.max = 1;
    30         progressNode.value = 1;
    31         console.log("Contents: " + contents);
    32     }
    33 };
    34 
    35 reader.readAsText(file);

    6、利用Object URL实现从本地读取文件到浏览器中显示

    Object URL是指向硬盘上文件的URL。假设,你需要在用户自己的系统中展现图片;而服务器根本不需要知道这个文件,所以就没有必要上传它。在之前的介绍中需要得到这个File对象的引用,读取数据到data URI 中,然后在 <img>元素中展现出来。但是仔细想想,图片已经在硬盘中存在了,为什么还要读取图片到另外一种形式然后来用它?如果创建一个object URL,你可以把它指派给<img>,直接从本地得到这个文件。

     

    在File API中定义了一个全局的对象叫URL,有两个方法。

     createObjectURL(),接收一个File的引用,返回一个对象URL。这个函数让浏览器创建和管理一个本地文件的URL。

    reovkeObjectURL(),让浏览器销毁URL,有效的释放内存。当然所有的对象URLs都会被释放一旦网页被销毁的时候,但利用这个函数释放内存是好的编码方式,反正我们也不再需要这些对象URL。

    现在浏览器对对象URL这部分的支持没有File API的其他部分支持的好。 现在Internet Explorer 10+ 和 Firefox 9+ 支持,chrome支持自己的webkitURL,Safari和Opera都不支持。

     1 var URL = window.URL || window.webkitURL,
     2     imageUrl,
     3     image;
     4 
     5 if (URL) {
     6     imageUrl = URL.createObjectURL(file);
     7     image = document.createElement("img");
     8 
     9     image.onload = function() {
    10         URL.revokeObjectURL(imageUrl);
    11     };
    12 
    13     image.src = imageUrl;
    14     document.body.appendChild(image);
    15 }

    乍一看,貌似很强大,URL本身还不是最大的安全问题,因为URL是动态绑定到浏览器上的,在其他机器上就没用了。但是如果跨域呢?

    File  API不允许在不同的域中使用对象URL。当一个URL被创建,它就被绑定到执行这个JS的网页的域中,所以在www.wrox.com中使用的对象URL在prp.wrox.com中不能使用(产生error)。然而,两个都来自www.wrox.com的页面,其中一个用iframe的方式嵌入到另外一个中,就可以使用同一个对象URL。

    对象URL只在文档创建它们时有效。当文档卸载,它们就都释放掉了。所以,不用担心把URL存储在本地的,以后使用;当页面卸载以后,它们就无效了。

    你可以在任何地方使用对象URL,浏览器会发出一个GET请求,包括images, scripts, web workers, style sheets, audio, and video。当浏览器执行POST请求时,比如form表单中设置为post方法时,将不能使用对象URL。

    7、利用Blobs分割文件

    在字符串和数组中,你可能对slice()很熟悉,Blobs的作用有点类似 slice()。Blobs接收三个参数:开始的字节位移,结束的字节位移,一个可选的MIME类型。如果没有指定MIME类型,新的Blob的数据类型与之前的一样。

    每一个Blob都只是代表对数据的指示,而不是数据本身,所以可以快速的创建新的Blob指向其他的子部分。需要利用slice()方法来实现。

    浏览器对slice()方法的支持不是很统一,FF中是通过mozSlice()来支持的,chrome通过webkitSlice()支持。其他浏览器暂时不支持。例子:

    function sliceBlob(blob, start, end, type) {
    
        type = type || blob.type;
    
        if (blob.mozSlice) {
            return blob.mozSlice(start, end, type);
        } else if (blob.webkitSlice) {
            return blob.webkitSlice(start, end type);
        } else {
            throw new Error("This doesn't work!");
        }
    }

    比如,你可以使用这个函数来分割一个大文件并用块的方式上传。每一个新的Blob都是独立的,即使它们之间的数据有交叉。

    (1)用老方法创建 Blobs。

    当文件对象在浏览器中出现,开发者意识到Blob对象非常有用,所以就想着能够不通过用户的交互来创建它。毕竟,任何数据都可以用Blob表达,而不用绑定到文件。浏览器很快就做出“响应”,创建BlobBuilder,它的目的就是为了在Blob对象中包裹数据。这不是一个标准的类型,在不同浏览器中都有不同的实现。ff(MozBlobBuilder),chrome(WebKitBlobBuilder),ie 10(MSBlobBuilder)。

    BlobBuilder通过创建一个新对象,然后调用append方法,传一个字符串或者ArrayBuffer或者Blob。一旦所有的数据被加载,调用getBlob()方法,传入一个MIME类型。

    例子:

    1 var builder = new BlobBuilder();
    2 builder.append("Hello world!");
    3 var blob = builder.getBlob("text/plain");

    例如,你可以用一个Blob创建一个网络线程而不需要为这个线程代码写一份单独的文件。这种技术已经存在于基本的网络线程中。

     1 // Prefixed in Webkit, Chrome 12, and FF6: window.WebKitBlobBuilder, window.MozBlobBuilder(在ff中用MozBlobBuilder,在chrome中用WebKitBlobBuilder
     2 var bb = new BlobBuilder();
     3 bb.append("onmessage = function(e) { postMessage('msg from worker'); }");
     4 
     5 // Obtain a blob URL reference to our worker 'file'.
     6 // 注意: window.webkitURL.createObjectURL() in Chrome 10+.
     7 var blobURL = window.URL.createObjectURL(bb.getBlob());
     8 
     9 var worker = new Worker(blobURL);
    10 worker.onmessage = function(e) {
    console.log(e.data);//msg from worker
    11 // e.data == 'msg from worker' 12 }; 13 worker.postMessage('',''); // Start the worker. 需要传参数

     上面的代码创建了一个简单的script脚本,然后创建了一个对象URL。对象URL被分配给一个网络线程worker.

    你可以调用append()任何次数来构建Blob的内容。

     (2)用新方法创建Blob

    用Blob构造器来创建。第一个参数就是 老方法中append()里面的东西,第二个参数是一个对象,包括新创建的Blob的属性。目前有两个属性的定义,指向Blob的MIME类型和结尾(可以是transparent默认或者是native)

    1 var blob = new Blob(["Hello world!"], { type: "text/plain" });

    这种方法暂时只在chrome中支持。ff13将会支持。

    结束:

    使用这些技术,你可以在图片上传前,缩放图片的大小(使用FileReader和canvas);你可以创建一个纯浏览器端的文件编辑器;你可以分割大的文件一块一块的上传。这些可能性都是无止境的,它们已经离我们越来越近了。

     
  • 相关阅读:
    Vue中v-on的指令以及一些其他指令
    Vue模板语法中数据绑定
    Vue介绍以及模板语法-插值
    JQ中的Ajax的封装
    跨域问题的解决?
    Ajax的快速入门
    如何使用npm的部分用法以及npm被墙的解决方法
    使用Node.js简单创建一个服务器
    机智云连接ESP8266--远程控制点亮RGB灯
    1、索引的概念和分类
  • 原文地址:https://www.cnblogs.com/lilyimage/p/2583062.html
Copyright © 2011-2022 走看看