基于HTML5的文件上传类设计

2015-06-24 15:42糜梅熊棠
电脑知识与技术 2015年2期

糜梅 熊棠

关键词:Javascript;HTML5;FormData;AJAX;异步;文件上传类

中图分类号:TP393 文献标识码:A 文章编号:1009-3044(2015)02-0072-03

2005年,Google在搜索web界面中推出了Google Suggest。Google Suggest使用AJAX创造出动态性极强的web界面:当您在谷歌的搜索框输入关键字时,JavaScript会把这些字符发送到服务器,然后服务器会返回一个搜索建议的列表。[1]其后,随着Google Reader、Google Map、Gmail等一大批产品的流行,AJAX这种与服务器交换数据并更新部分网页的艺术迅速的流行起来。但是,AJAX一直没有实现对文件对象的异步上传,直到HTML5的出现。

1 FormData对象

在HTML5标准中,XMLHttpRequest Level 2添加了一个新的接口FormData。利用FormData对象,我们可以通过JavaScript用一些键值对来模拟一系列表单控件,我们还可以使用XMLHttpRequest的send()方法来异步的提交这个“表单”。比起普通的AJAX,使用FormData的最大优点就是我们可以异步上传一个二进制文件。[2]

1.1 构造

使用new方法构造一个FormData实例:

var form = new FormData([formElement]);

参数formElement为可选,可以包含任何形式的表单控件,如一个文本框,或是一个表单对象。

1.2 append方法

使用append方法可以给当前FormData对象实例添加一个键/值对:

form.append(name,value,[filename]);

name表示一个字段名称,value表示一个字段值。value可以是一个字符串,或者一个二进制大对象或文件;如果给出的数据是其它类型比如整数型,会被自动转换成字符串型[3]。当value为一个二进制大对象或文件时,可选参数filename将以字符串的形式发送给服务器。

1.3 delete方法

使用delete方法可以删除当前FormData对象实例的一个键/值对:

form.delete(name);

1.4 get方法

使用get方法可以读取当前FormData对象实例对应键的值:

var value = form.get(name);

此外,还有以数组形式返回所有键/值对的getAll方法,检查否是含有某键的has方法,和更新已有键/值对的set方法。delete、get、getAll、has、set方法仅支持Chrome、Opera浏览器的部分版本[4]。

2 表单

HTML5的文件API有一个FileList接口,可以通过e.dataTransfer.files拖拽事件传递的文件信息获得本地文件列表,因此理论上可以使用任何DOM替代文本域作为拖拽区域。为了兼容不支持HTML5的浏览器,仍然需要使用文本域来访问本地文件系统。

utf8和authenticity_token字段由框架自动生成,用来防止外部提交。file[file][]字段为文件域,支持多文件,文件列表为数组形式;文本域的样式设置为同外部DIV同宽同高,且不透明度为0。图1中FILE图案的位置对应为文本域的浏览按钮,点击可打开文件选择对话框。

work方法以this.FileField文本域为起点查找父节点,通过迭代方式最终获得表单对象。将表单对象所属控件按键/值对的形式存入this.data以便于多次提交。this.uploader一般情况下应等于表单的动作,也可以通过对实例属性赋值进行重设。在上传开始前设置文本域为不可见以防止在多个大文件上传的过程中用户再次操作文本域造成错误。如果页面上没有进度条,则将主动创建的进度条置于文件域的位置,如图4所示,这样不会因为新页面元素的加入造成页面变形。up方法以异步方式上传数据,需用到FormData对象;IE6等不支持HTML5的浏览器会运行错误,因此使用try{}catch(e){}方法进行错误控制,使IE6等浏览器运行同步提交表单动作,即form.submit()。

work方法的参数有3个,succFunc、errFunc和doneFunc。succFunc是单个文件上传成功后调用的方法,errFunc是出现异常时调用的方法,doneFunc是所有文件上传完成后调用的方法。这3个方法都将作为参数传递给up方法。调用方法为:

up(succFunc,errFunc,doneFunc,this.FileField,this.count,up,this.extension,this.data,this.uploader,this.progressBar,this.tip);

3.2.2 up方法

up方法执行一个异步上传任务,包括提交表单,上传文件,显示进度及信息,按照上传结果及计数器决定调用方法等。

当文件域的multiple属性值为“multiple”时,文件列表以数组形式存在,访问方法为var fileObj=this.FileField.files[file_index]。fileObj为当前文件对象,file_index为计数器的当前值。fileObj.name为当前文件对象的文件名,使用正则表达式/[^\.]+$/可以得到文件的后缀名ext。将ext与this.extension比较就可以知道当前文件的类型是否合法。当然,前端限制总是可以绕过的,只能作为一种用户体验优化手段;必须在后端对文件类型的合法性进行严格的检验。如果文件非法,启动异常处理程序,否则创建FormData实例form,并使用form.append方法将this.data中的数据添加到form中,添加时需要区分this.data中的数据是数组类型还是对象:

同样的方法将当前文件对象也添加进form,form.append(this.filefield.name,fileObj)。创建XMLHttpRequest实例carrier并上传form对象的方法与一般的AJAX处理过程相同,不再赘述。Carrier的upload事件触发添加事件监听,事件类型为"progress",事件处理方法为progressFunction。Carrier上传结束后计数器加1。异步上传网络异常时启动异常处理程序,否则调用succFunc处理服务器返回结果;如果服务器返回的数据表明上传不成功,则启动异常处理程序,否则比较计数器与文件域中文件列表数;如果计数器小于文件数,则迭代调用up方法;如果计数器等于于文件数,则表明文件上传完毕,调用doneFunc方法。

up方法的参数有succFunc,errFunc,doneFunc,filefield,file_index,next_func,extension,data,uploader,progressBar和tip。next_func为检测到还有文件未上传时执行的方法,即up方法本身。其余参数文中已有说明。这些参数在迭代时将传递给next_func作为参数。

3.2.3 progressFunction方法

4 异常处理

异常处理方法不属于drawUp类的方法,根据实际需要另外定义,作为参数传递给drawUp类的对象方法work。定义方法error为出现异常时的调用方法。error需要完成两个工作:1、根据实际需要完成对错误的处理;2、决定是否进入下一次上传。此处省略处理错误的代码,修改第2节的HTML5Uploader()脚本为:

error的参数result是XMLHttpRequest实例carrier的运行状态carrier.status或返回结果carrier.responseText。error对这个值进行类型分析或文本分析,然后执行具体的错误处理流程,此处不再赘述。

5 结束语

本文构建的文件上传类能够在支持HTML5的浏览器中实现拖拽多个文件、识别文件类型、异步上传文件、显示上传进度、上传后处理等功能;对于不兼容HTML5的浏览器能够实现传统的同步方式上传,实现了设计目标。

参考文献:

[1] W3School. AJAX 简介[EB/OL]. [2015-05-22]. http://www.w3school.com.cn/ajax/ajax_intro.asp.

[2] ziyunfei TooBug teoli. FormData[EB/OL].(2015-02)[2015-05-22].https://developer.mozilla.org/zh-CN/docs/Web/API/FormData.

[4] Grissess cpigat cgack kscarfone Jeremie premjoy saneyuki_s Kabe Sicking ernestd mkato Sheppy ziyunfei evilpie teoli Yanmorin mattflaschen ethertank chrisdavidmills Callahad leachlife4 philoyche. FormData [EB/OL].(2015-04)[2015-05-22]. https://developer.mozilla.org/en-US/docs/Web/API/FormData.