学无所长,一事无成
分类: JavaScript
2015-05-26 11:41:49
Project owner: | Mike Wilcox |
---|---|
Author: | Mike Wilcox |
since: | 1.6 |
A widget that adds functionality to a standard HTML file input which allows file uploading to a server. The widget hides the actual uploader and substitutes a dijit.form.Button, so that the file input matches the rest of the user interface. If the browser supports the HTML5 file input specification, that functionality is used. If it is not supported (IE or older browsers) plugins are available to enhance the Uploader.
dojox.form.Uploader 用于取代 dojox.form.FileUploader,并且功能进行了增强。The multiple problems created by Flash are avoided because it is not used in Mozilla and Webkit browsers. Support for FileUploader will cease as of 1.6, but the code will remain until 2.0 for backwards compatibility.
- Uploader 是一个 Dijit, 并且支持所有其他 form widget 的相同功能。FileUploader (注意是另外一个 Digit)也这样宣称,但实际上它是有问题的,因为它是基于 Flash plugin 实现随后的 build process and dependency。
- Uploader 可以放置在 form 中 “正常工作”。实际上 Uploader 是将 form 表单的 submit event 封装起来,并取代了 form 的职能,实现 field 输入值的收集,以及利用 form 表单的 action 属性上传数据到服务端(或者将 form 表单的url 属性传递给 Uploader)。
- 支持 tabIndex 属性。
- 有一个附加小部件 dojox.form.uploader.FileList 可以显示选择的文件集合,并显示上传进度。
当采用编程方式使用 Uploader 时,你不能使用 require() 中的引用参数 - 你必须使用全局参数。这是因为plugins 重定义了原始的 Uploader class,而 AMD 是不会有时机这样干的。因此,以下代码不会正常工作:
因为 Uploader 使用当前的 form 表单,因此你必须将表单的 enctype 属性设置为 “multipart/form-data”,这样才能使其上传文件。
Uploader 仅仅是模拟实现的 HTML5 file inputs 的功能,因此 FileUploader 中的某些功能在 Uploader 中尚未实现。比如一个比较重要的功能缺失,往当前已选择的文件集中添加或删除文件。目前已有计划要实现这个功能。
HTML5 规范中定义了 File 掩码(用于限定选择的文件类型),但由于浏览器功能缺失。此功能不支持。
Uploader 有几种不同的使用方式。
Uploader 如不指定 plugins 则采用 “Form” 表单模式。这种模式不会采用 Ajax 方式上传。这种方式要求你自己处理上传,不管你是通过 Ajax 处理,还是通过 POST后刷新整个页面。在测试文件中(dojo子目录下有)只有 form POSTs 会正常工作,页面会跳转到 UploadFile.php 。Multiple file selection is used in browsers that support it, and in the others, multiple selections are added one at a time by adding file inputs.
HTML5 上传插件不支持 IE, it is more of a base class for IFrame or Flash, or used in cases where IE is not a requirement. 对于支持 HTML5 的浏览器,这个 puglin 提供 Ajax 上传的能力。
IFrame 插件在 IE 中使用 IFrame 进行上传。其他浏览器将使用 HTML5 插件,除非强行指定了 force=”iframe” 。
Flash 插件将在非 HTML5 浏览器中使用 SWF 进行上传。所有其他的浏览器将使用 HTML5 插件,除非强行指定了force=”flash” 。只所以要提供 force=”flash” ,是因为 Flash 中有些功能 HTML5 尚不具备。但还是不推荐采用此种方式,因为 Mozilla 和 Webkit 使用 Flash 插件会遇到很多问题:
- Changing the display style on the DOM element that holds a SWF will reset the SWF. This makes it difficult to support Flash in Dijit Tabs and Dialog boxes.
- Initialization of a SWF is not always consistent and occasionally throws errors.
- HTTPS support in Mozilla is problematic.
这些问题在 IE 中都不会发生。
要使用 Uploader很简单,先 require ,然后在表单中的 input 上添加上合适的 data-dojo-type 属性:
下面例子演示通过编程创建 Uploader,使用的是 Flash plugin:
Uploader 的一个主要属性是 “name”,它被用作创建的 file input 的 name 属性,或者是 Flash 绑定到的每个文件的 field ame 。缺省名字是 “uploadedfile”,同指明的 UploadFile.php 协同工作。HTML5 规范定义此属性是一个 array-like ,因此在 field name 后用方括号括住。如果使用的是支持 HTML5 的浏览器,Uploader 会添加括号。同时会在 name 后添加 “s” 帮助 server script 识别 file data。如果是使用 Flash plugin,Uploader 会在 name 后添加 “Flash”,or whatever the “flashFieldName” property is set to。如果是使用的标准 file input (“Form” 或 IFrame),name 保持原样。
几种不同的 name 属性样式有助于 server page 知道发送的是什么数据从而采用适当的处理方式。
- flashFieldName 是用于追加到 name 属性后的文本。这个有助于 server 了解它要处理的是什么类型的文件数据。
- multiple 是否允许选择多个文件。
- url 如果表单中没有指明 action ,那需要提供一个 url 进行文件上传。
- label 指明button 上显示的文字。
- tabIndex 缺省为 “0”。修改这个值可以可以调整页面的 tab order 顺序。
Flash plugin 还有一些针对上传文件的其他属性。
因为 Uploader 没有 plugins 将无法上传,其仅有如下方法:
- reset 清除选择文件列表。
- getFileList 返回一个代表 file data 的对象数组。
启动 plugin ,如下方法就可用了:
- upload 此方法上传文件以及作为参数传入的任何数据。
- submit 此方法上传文件,并在 form element 作为参数传入时,将其转化为 JavaScript object。
服务器端上传的文件会存入一个临时目录。一个误解是你会以为需要服务端语言来实现这些,其实不是。接收上传文件是由你的 server 处理的,比如 Apache 或 IIS 。而将文件从临时目录放到某个 upload 目录下就是你的任务了。不管是 HTML 或 Flash,上传任务都将由多个 transfer 完成(the payload is done with a multipart transfer)。一旦上传结束,server 端脚本(server script) 将被调用。
在 Flash 方式上传多个文件时,图片会并行上传(除非指明 deferredUploading=true),但 server script 却只能一次接收一个文件。因此如果上传了五个文件,则 server script 会被调用五次。
在 HTML 方式上传多个文件时,所有文件一次性一起上传,在全部五个文件都成功上传到临时目录后,server script 仅会被调用一次。对于传统的 HTML (表单模式或 IFrame plugin),每个文件引用的方式采用数字序列:uploadedfile0, uploadedfile1, uploadedfile2, 等等。对于 HTML5 方式的上传,server script 会寻找 “uploadedfiles” (末尾多了个 “s”哦)。Uploader 会在 name 后添加方括号以匹配规范(“uploadedfiles[]”)。最终结果就是上传的多个文件将作为数组传递给 server script。
With a multipart request the POST data is the contents for the first part and the uploaded files is an array (or an object) of each additional part. 参考你的 server 文档了解如何引用 files (下一节使用 PHP 示例)。
返回数据需要按照特定要求进行格式化,对于 Flash 和 HTML 格式有所不同。参考下面 Server Side Return Data 一节。
Uploader 小部件中带有一个可运行的 PHP 文件,dojox/form/tests/UploadFile.php, to use as a reference for how your server side code should work. UploadFile.php 有两个依赖文件, dojo/tests/resources/JSON.php 用于将返回结果转化为 JSON 字符串,dojox/form/tests/cLog.php 用来记录日志信息到一个文本文件,存储位置相对于 PHP 文件而定。
UploadFile.php 以如下四种方式之一运行:
PHP 文件会检查 header 搜索 Uploader 的参数集合。不管你如何设定参数,server 端必须对应匹配。
对于 HTML uploader 所对应的 field name 同样运作。唯一不同就是你使用 HTML 进行多个文件上传时, this essentially continues to add fileInputs to the form, and in doing so, appends numbers to the fileInput field names, starting with ‘0’. That’s why one file fieldname will look like “myFieldName” but two files will look like [ “myFieldName0”, “myFieldName1” ] to the server side code.
服务器端如何返回数据并不难,但很重要。如果设置错误,会导致报错,以及 Uploader 的 “onComplete” 无法触发。
注意 对于 Flash uploader 和 HTML uploader 需要不同格式的返回数据。你需要检查 post 数据来判定使用哪种类型的返回数据
如果在 post 数据中发现了 uploadedfilesFlash ,而且客户端使用的是 Flash,那么需要的所有返回数据就是一个 key-value 字符串,在函数末尾,简单地将其返回即可。Flash 会将这些 key-value 对存入一个 object 传递给 javascript。同时你需要插入一个 exit 或者其他什么指定用来终止剩余代码的执行。例子如下:
对非 PHP 程序员,做点解释:
最终返回给 Flash 的数据会类似如下:
This string should be returned, or printed, or echoed.
You can add an error key if one file was in error; say if it was not of the correct type. This error code or message will be returned in the onComplete dataArray. It's important to note that as far as the Uploader is concerned, everything was a success. It's up to your custom code to test for this error.
The return string with an error might look like:
You can also send back arbitrary parameters from your server-side script using this comma-delimited format. For example, adding variables foo and abc:
Then you can access these variables in the client-side functions using dataArray[i].additionalParams.foo and dataArray[i].additionalParams.abc.
如果使用 IFrame plugin ,客户端的代码比较复杂,as reading back from an iframe presents problems. 要想跨浏览器精准识别 iframe 的返回数据,代码需要包裹在 你可以在 UploadFiles.php 文件非常靠后的位置看到这些代码。注意 textarea 需要位于 PHP 的外部。例如:
如果你对如何捕获 onComplete 的触发还有疑问,先看下这个代码吧。通常问题都是服务器端代码不管什么原因没有捕获 field name (或许是 client 和 server 两边的 names 不一致),and the code is falling to the end of the page and returning a textarea when it shouldn't.
下面这个例子展示如何使用 Flash 或 IFrame 应对两种不同状况(浏览器支持或不支持 flash)。