您的位置:首页 > 产品设计 > UI/UE

FineUI秘密花园(七) — 上传控件

2017-05-17 11:01 225 查看
FineUI直到V3.0才内置了自己的上传控件,为什么唯独上传控件姗姗来迟,这其中的缘由是啥?之前又是如何实现上传功能的呢?下面听我慢慢道来。

 


AJAX请求与文件上传请求的对比

 

普通的AJAX请求的请求头和请求正文:





 





 

文件上传请求的请求头与请求正文:









 

可见,普通的AJAX请求其Content-Type为application/x-www-form-urlencoded,其请求正文是键值对组成的查询字符串;而文件上传请求其Content-Type为multipart/form-data,其请求正文不仅分段包含正常的表单字段,而且包含要上传文件的内容。

 

也就是说两种请求方式完全不同,要在AJAX环境中实现文件上传,最通用的做法是用一个临时生成的IFrame来提交文件。而这个过程将会比较复杂,这也是FineUI一直没有实现自己的文件上传控件的原因(后来发现ExtJS支持这个过程,所以就有了FineUI自己的FileUpload控件)。

 

 


之前实现文件上传的方式

由于之前FineUI没有自己的FileUpload控件,只好求助于ASP.NET的FileUpload控件,并且由于文件上传的请求不能是AJAX的请求,所以只好采用整个页面回发的方式(这也是很多网友所抱怨的地方),参见这个示例

1:  <f:PageManager ID="PageManager1" runat="server" EnableAjax="false" />

2:  <asp:FileUpload ID="FileUpload1" runat="server"></asp:FileUpload>

3:  <asp:Button ID="btnCloseWindow2" runat="server" Text="上传文件" OnClick="btnCloseWindow2_Click"></asp:Button>


 

1:  protected void btnCloseWindow2_Click(object sender, EventArgs e)

2:  {

3:      if (FileUpload1.HasFile)

4:      {

5:          FileUpload1.SaveAs(Server.MapPath("~/upload/" + FileUpload1.FileName));

6:      }

7:      Alert.ShowInTop("文件上传成功!");

8:  }


 

显示效果如下图所示:





 

正如前文所述,这个实现有两个突出问题:1. 文件上传框风格和整个页面风格不搭配。 2. 上传时是整个页面回发,和FineUI默认的AJAX风格也不搭。

 

 


现在的文件上传方式

现在就简单多了,并且也漂亮多了,参考这个示例





 

1:  <ext:SimpleForm ID="SimpleForm1" BodyPadding="5px" runat="server" EnableBackgroundColor="true"

2:      ShowBorder="True" Title="表单" Width="350px" ShowHeader="True">

3:      <Items>

4:          <ext:TextBox runat="server" Label="用户名" ID="tbxUseraName" Required="true" ShowRedStar="true">

5:          </ext:TextBox>

6:          <ext:FileUpload runat="server" ID="filePhoto" EmptyText="请选择一张照片" Label="个人头像" Required="true"

7:              ShowRedStar="true">

8:          </ext:FileUpload>

9:          <ext:Button ID="btnSubmit" runat="server" OnClick="btnSubmit_Click" ValidateForms="SimpleForm1"

10:              Text="提交">

11:          </ext:Button>

12:      </Items>

13:  </ext:SimpleForm>

 


1:  protected void btnSubmit_Click(object sender, EventArgs e)

2:  {

3:      string fileName = DateTime.Now.Ticks.ToString() + "_" + filePhoto.FileName;

4:      if (filePhoto.HasFile)

5:      {

6:          filePhoto.SaveAs(Server.MapPath("~/upload/" + fileName));

7:      }

8:  }

 


下面来看看FileUpload的属性:
ButtonText:按钮文本。
ButtonOnly:是否只显示按钮,不显示只读输入框。
ButtonIcon:按钮图标。
ButtonIconUrl:按钮图标地址。
PostedFile:上传的文件。
HasFile:是否包含文件。
FileName:上传文件名。

 

还有一个重要的方法 SaveAs,用来将上传的文本保存到服务器上。

 

 












观察文件上传的过程

在文章的最开始我们提到,ExtJS是通过临时创建一个IFrame来提交文件请求的,下面就通过一个示例来仔细观察这个过程。

首先在Firefox中打开示例页面: http://extasp.net/form/fileupload.aspx

打开Firebug,启用脚本调试功能,在右侧搜索框中输入 Ext.extend(Ext.data.Connection ,将定位到Ext.ajax.request函数,所有的AJAX请求都是由这个函数发出了。





 

注意往下观察,会看到这样的代码:

1:  url = url || form.action;

2:  if(o.isUpload || (/multipart\/form-data/i.test(form.getAttribute("enctype")))) {

3:          return me.doFormUpload.call(me, o, p, url);

4:  }


很明显,文件上传的代码都是在doFormUpload函数内完成的,下面是此函数的简化版本(已经删除了很多不影响理解的代码):



1:  doFormUpload: function (o, ps, url) {

2:      var id = Ext.id(),

3:          doc = document,

4:          frame = doc.createElement('iframe'),

5:          form = Ext.getDom(o.form),

6:          encoding = 'multipart/form-data';

7:   

8:      Ext.fly(frame).set({

9:          id: id,

10:          name: id,

11:          cls: 'x-hidden'

12:      });

13:      doc.body.appendChild(frame);

14:   

15:      Ext.fly(form).set({

16:          target: id,

17:          method: POST,

18:          enctype: encoding,

19:          encoding: encoding,

20:          action: url || buf.action

21:      });

22:   

23:      function cb() {

24:          var me = this,

25:              r = {

26:                  responseText: '',

27:                  responseXML: null,

28:                  argument: o.argument

29:              },

30:              doc, firstChild;

31:          doc = frame.contentWindow.document || frame.contentDocument || WINDOW.frames[id].document;

32:          if (doc) {

33:              r.responseText = doc.body.innerHTML;

34:              r.responseXML = doc.XMLDocument || doc;

35:          }

36:          me.fireEvent(REQUESTCOMPLETE, me, r, o);

37:      }

38:      Ext.EventManager.on(frame, LOAD, cb, this);

39:      form.submit();

40:  }


下面我们来分析一下这个函数表达了哪些思想:

1. 首先第8行到13行是创建一个空的iframe标签,并追加到页面的底部。此时的页面如下图所示:





 

2. 第15到21行非常重要,注意target: id这个设置,其实是将页面中表单的提交目标改变为当前窗体中新创建的iframe,而不是当前窗体了。

 

3. 第23行到37行定义回调函数cb。

 

4. 第38行将回调函数注册为iframe加载完毕时执行的函数。

 

5. 第39行提交表单。注意,此时表单是在新创建的iframe中提交的!

 

6. 再来看看回调函数cb中的处理,首先获取iframe中body的内容并赋值给响应对象的responseText属性,然后触发此次请求的完成事件。此时的页面效果如下图所示:





 

7. 至此,完成了文件上传的AJAX效果。

 

 


小结

文件上传控件用起来方便,不过内部实现却不是一帆风顺的,这也是它姗姗来迟的原因之一。不过这也是FineUI控件的目标,内部实现可以非常复杂,但是对开发人员的接口一定要尽量简单。

下一篇文章我们会仔细考察下拉列表在FineUI中的用法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  FineUI extjs