2025-05-23

文件上傳很常見,也有好些方法,不過我見過的大多是基於flash的,也有用XMLhttpResponse來提交文件的,其實大可不必這麼麻煩,我這裡介紹一種更具兼容性的用法,利用iframe來曲線實現無刷新頁面文件上傳功能,這種方法其實也很常見瞭。
  iframe上傳文件原理是這樣的:首先input file控件本身是被表單包含的,表單屬性必須設置為enctype="multipart/form-data",才能上傳任意文件。但是僅僅有這個還不行, 因為提交表單後,它會自動刷新頁面,為瞭不讓它離開本頁,我們可以在這個提交的頁面上動態生成一個隱藏的iframe,但是別忘瞭在表單上再添加一個屬性target,並且指定為iframe的name,這樣表單提交後,服務器才會將返回的結果會寫在iframe裡。最後在從這個iframe裡獲取數據就可以瞭。
  原理上不難理解,也不難實現。在這上面還可以擴展出更多的功能,比如上傳前判斷文件類型,大小之類的,添加一個加載的過程等等。不過在實現的過程,還是遇到瞭幾個難點:一個是獲取文件信息,這個在不同的瀏覽器上,獲取的方法不盡相同;另外一個是獲取iframe裡的內容。這些問題的解決方法,我沒有很好的解決,不過貌似也沒有什麼大問題,所以我把解決的方法寫在這裡。
獲取文件信息:我這裡隻是實現瞭獲取文件名稱的功能。
 1 getFile: function() {
 2   var fileInfo = {};
 3   var isIE = !!window.ActiveXObject;
 4   // var isIE6 = isIE&&!window.XMLHttpRequest;
 5   // var isIE8 = isIE&&!!document.documentMode;
 6   // var isIE7 = isIE&&!isIE6&&!isIE8;
 7   var path = '';
 8   if(isIE) {
 9     path = document.getElementById(this.config.id).value;
10     fileInfo.fileName = path.slice(path.lastIndexOf('\\')+1);
11   } else fileInfo.fileName = document.getElementById(this.config.id).files[0].name;
12   return fileInfo;
13 }

獲取iframe的內容:
document.getElementById("iframe").find('body').html();
  我這裡先展示一個基本的上傳代碼,供各位參考。 我這個是不帶界面的,純邏輯部分。頁面須有個<input type='file' id='uploader' name='file'/>標簽,然後可以這樣調用:
var uploader = new FileUploader({
   action: 'url', // 上傳地址
   onChange: function() {}, // 上傳前
   loading: function() {}, // 上傳過程中
   onComplete: function() {} //上傳完成後

點擊按鈕選擇一個文件後就會立即提交。
  完整代碼:
 1 function FileUploader(config) {
 2     this.config = config;
 3     this.input = $('#'+this.config.id);
 4     this.action = this.config.action || '';
 5     this.method = this.config.method || 'post';
 6     this.type = this.config.type || 'json';
 7     this.init();
 8 }
 9 FileUploader.prototype = {
10     init: function() {
11         var that = this;
12         this.addListener('change', function() {
13             if(that.config.onChange) {
14                 var res = false;
15                 res = that.config.onChange.call(this, that.getFile());
16                 if(!res) return false;
17             }
18             that.load();
19         });
20     },
21     load: function() {
22         var that = this;
23         this.wrap();
24         this.send();
25         if(that.config.loading) that.config.loading.call(that);
26         $('iframe').bind('load', function() {
27             var data = that.getResponse(document.getElementById("hidden_frame")).find('body').html();
28             data = data.replace(/<pre.*>(.*)<\/pre>/, "$1");
29             if(that.config.onComplete) {
30                 if(that.type == 'json') data = eval('('+data+')');
31                 that.config.onComplete.call(this, data, that.input);
32             }
33             // this.input.unwrap();
34             $(this).remove();
35         });
36     },
37     getResponse: function(iframe) {
38         var doc = $(iframe).contents();
39         return doc;
40     },
41     remove: function() {
42         this.input.remove();
43     },
44     getFile: function() {
45         var fileInfo = {};
46         var isIE = !!window.ActiveXObject;
47         var isIE6 = isIE&&!window.XMLHttpRequest;
48         var isIE8 = isIE&&!!document.documentMode;
49         var isIE7 = isIE&&!isIE6&&!isIE8;
50         var path = '';
51         if(isIE) {
52             path = document.getElementById(this.config.id).value;
53             fileInfo.fileName = path.slice(path.lastIndexOf('\\')+1);
54         } else fileInfo.fileName = document.getElementById(this.config.id).files[0].name;
55         return fileInfo;
56     },
57     send: function(cb) {
58         var that = this;
59         this.input.parent('form').submit();
60     },
61     wrap: function() {
62         this.input.wrap(
63                 '<form enctype="multipart/form-data"'+
64                     'action="'+this.action+'" method="'+this.method+'" target="hidden_frame">'+
65                 '</form>'
66         );
67         this.input.parent('form').after(
68                 '<iframe name="hidden_frame" id="hidden_frame" src="javascript:false;" style="display:none"></iframe>'
69         );
70     },
71     addListener: function(type, cb) {
72         if(type == 'change') this.input.bind('change', cb);
73     }
74 };

 摘自  bilipan
 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *