利用iframe无刷新上传文件的坑
頁(yè)面里經(jīng)常要用到文件上傳的功能,而且要求頁(yè)面不刷新,先說(shuō)一下原理:頁(yè)面里放一個(gè)file控件和submit按鈕,外面用form表單包住,給form表單加上對(duì)應(yīng)的屬性值,action、method、entype、name,到這一步,能上傳文件了,但是這樣上傳文件會(huì)刷新頁(yè)面,這不是我們想要的。我們要的是文件上傳時(shí)不刷新頁(yè)面,那么也簡(jiǎn)單,在頁(yè)面里放一個(gè)iframe,設(shè)置它的寬高為0,這里有兩個(gè)坑:
1、需要設(shè)置iframe的name值與form的target屬性值一樣,意思就是把form表單上傳文件的刷新轉(zhuǎn)嫁到iframe里去了;
2、form表單的enctype屬性值必須設(shè)置成multipart/form-data,將文件轉(zhuǎn)換成文件流供后端接收;
代碼如下:
<iframe name="fileUpload"></iframe> <form method="post" action="xxxx" enctype="multipart/form-data" name="fileForm" target="fileUpload"><input type="file" class="fileInput" name="fileInput"><input type="submit" value="提交" /> </form>頁(yè)面(這里為了看到效果,就不將iframe的寬高設(shè)為0了):
事情就這么愉快地結(jié)束了嗎?當(dāng)然沒(méi)有,離國(guó)慶節(jié)還有那么些天,不要著急。
到這里文件能上傳了,頁(yè)面也不會(huì)刷新,那么還差什么?當(dāng)然是精益求精--優(yōu)化啦。怎么優(yōu)化?假如頁(yè)面里有三個(gè)地方需要上傳不同類型的文件,最好的辦法肯定不是在頁(yè)面里將代碼copy三份,然后就這樣用,這是普通開(kāi)發(fā)的做法,我們可以利用js動(dòng)態(tài)生成上面這些代碼,需要上傳文件的地方,一個(gè)函數(shù)加參數(shù)就搞定了,代碼如下:
/*2014年9月18日17:39:47 By 王美建*/ function ajaxUpload(opt){/*參數(shù)說(shuō)明:opt.frameName : iframe的name值;opt.url : 文件要提交到的地址;opt.fileName : file控件的name;opt.format : 文件格式,以數(shù)組的形式傳遞,如['jpg','png','gif','bmp'];opt.callBack : 上傳成功后回調(diào);*/var iName=opt.frameName; //太長(zhǎng)了,變短點(diǎn)var iframe,form;//創(chuàng)建iframe和form表單iframe = $('<iframe name="'+iName+'" />');form = $('<form method="post" style="display:none;" target="'+iName+'" action="'+opt.url+'" name="form_'+iName+'" enctype="multipart/form-data" />');file = $('<input type="file" name="'+opt.fileName+'" />');file.appendTo(form);//插入body $(document.body).append(iframe).append(form);//觸發(fā)瀏覽事件,選擇文件 file.click();//選中文件后,驗(yàn)證文件格式是否符合要求file.change(function(){//取得所選文件的擴(kuò)展名var fileFormat=$(this).val().exec(/\.[a-zA-Z]+$/)[0].substring(1);if(opt.format.join('-').indexOf(fileVal)!=-1){form.submit();//格式通過(guò)驗(yàn)證后提交表單;}else{iframe.remove();form.remove();alert('文件格式錯(cuò)誤,請(qǐng)重新選擇!');}});//文件提交完后iframe.load(function(){var data = $(this).contents().find('body').html();opt.callBack(data);iframe.remove();form.remove();}) } 使用方法:在頁(yè)面里放一個(gè)按鈕Btn,點(diǎn)擊Btn時(shí)觸發(fā)ajaxUpload方法,ajaxUpload方法內(nèi)部自動(dòng)創(chuàng)建上傳所需要的元素并自動(dòng)觸發(fā)file.click()事件供用戶選擇文件,選中文件后自動(dòng)驗(yàn)證文件格式并提交,然后返回后端返回的結(jié)果,到這里,問(wèn)題解決了80%,為什么不是100%?ajaxUpload方法在IE8以上及火狐、chrome瀏覽器都沒(méi)有問(wèn)題,但在IE8及以下的瀏覽器上傳文件會(huì)提示:沒(méi)有權(quán)限!這是因?yàn)?strong>低版本的IE做了安全限制,file控件必須由用戶主動(dòng)點(diǎn)擊觸發(fā)選擇的文件才可以上傳,而不能使用js的click事件來(lái)模擬點(diǎn)擊觸發(fā)。在此我又想說(shuō),IE我~!@#¥%……&*()——……。 辦法總比困難多,既然一定要由用戶點(diǎn)擊來(lái)觸發(fā),那么直接把頁(yè)面里的按鈕替換成file控件吧,iframe和form還是動(dòng)態(tài)創(chuàng)建,當(dāng)用戶點(diǎn)擊file控件選擇文件后,會(huì)觸發(fā)file控件的chang事件,給file控件的change事件綁定ajaxUpload方法并將file控件的id傳進(jìn)去,ajaxUpload方法通過(guò)id獲取file控件并將file控件appendTo到動(dòng)態(tài)創(chuàng)建的form里,之后的步驟與上面無(wú)異——驗(yàn)證格式→提交表單→觸發(fā)回調(diào)。細(xì)心的同學(xué)會(huì)發(fā)現(xiàn),選擇文件后,file控件會(huì)appendTo到form表單里,那頁(yè)面里放file控件的地方不是空了么?并且,表單提交后,file會(huì)隨著form一起被remove掉,所以,在file控件appendTo到form前,先建一個(gè)變量P將file控件的父級(jí)存起來(lái),form表單提交之后,先將file控件appendTo回到P里面,當(dāng)然,file控件appendTo到form時(shí),file控件依然會(huì)在頁(yè)面里消失,所以頁(yè)面里的Btn要保留,把file控件定位在Btn上面,透明度設(shè)置成0,這樣點(diǎn)擊Btn實(shí)際上點(diǎn)擊的是蓋在上面的file控件,這樣即使file控件被appendTo到form里面,用戶也不會(huì)察覺(jué)到什么變化,問(wèn)題迎刃而解!兼容的寫法如下:/*2014年9月19日11:11:07 By 王美建*/
function ajaxUpload(opt){/*參數(shù)說(shuō)明:opt.id : 頁(yè)面里file控件的ID;opt.frameName : iframe的name值;opt.url : 文件要提交到的地址;opt.format : 文件格式,以數(shù)組的形式傳遞,如['jpg','png','gif','bmp'];opt.callBack : 上傳成功后回調(diào);*/var iName=opt.frameName; //太長(zhǎng)了,變短點(diǎn)var iframe,form,file,fileParent;//創(chuàng)建iframe和form表單iframe = $('<iframe name="'+iName+'" />');form = $('<form method="post" style="display:n1one;" target="'+iName+'" action="'+opt.url+'" name="form_'+iName+'" enctype="multipart/form-data" />');file = $('#'+opt.id); //通過(guò)id獲取flie控件fileParent = file.parent(); //存父級(jí) file.appendTo(form);//插入body $(document.body).append(iframe).append(form);//取得所選文件的擴(kuò)展名var fileFormat=/\.[a-zA-Z]+$/.exec(file.val())[0].substring(1);if(opt.format.join('-').indexOf(fileFormat)!=-1){form.submit();//格式通過(guò)驗(yàn)證后提交表單;}else{file.appendTo(fileParent); //將file控件放回到頁(yè)面 iframe.remove();form.remove();alert('文件格式錯(cuò)誤,請(qǐng)重新選擇!');};//文件提交完后iframe.load(function(){var data = $(this).contents().find('body').html(); file.appendTo(fileParent);iframe.remove();form.remove();opt.callBack(data);}) } 國(guó)際慣例,到這里,方法已經(jīng)接近完美了,為什么是接近?來(lái)看一張圖片:
結(jié)構(gòu)代碼:
.fileInput{ position: absolute;left: 0;top: 0;height: 30px; filter:alpha(opacity=60);opacity:0.6; background-color: transparent;} .btn{width: 200px;height: 30px; margin: 100px auto; background-color: yellow; text-align: center; line-height: 30px; overflow: hidden; display: block; position: relative;} <div class="btn">選擇文件<input type="file" class="fileInput" name="fileInput"></div>
這就是放在頁(yè)面里的file控件,外面用一個(gè)div包住,在IE10及以下瀏覽器中,用戶單擊紅色框部分是不會(huì)彈出文件選擇框的,必須單擊藍(lán)色部分或雙擊紅色部分才行,要讓藍(lán)色部分占滿外面的div怎么做到呢?用css設(shè)置寬度只會(huì)增加紅色部分的寬度,這時(shí)我們會(huì)發(fā)現(xiàn)藍(lán)色部分是有字的,對(duì),可以通過(guò)設(shè)置font-size來(lái)使藍(lán)色部分變寬,然后給file控件加上dir="rtl",這會(huì)讓瀏覽按鈕移到左邊,再給.btn加上overflow:hidden,可以發(fā)現(xiàn)瀏覽按鈕已經(jīng)占滿整個(gè)div了,如下圖:
到這里才真正完成了100%,最后,我們還可以給file控件設(shè)置accept屬性,限制可選文件格式(IE8及以下不支持該屬性),別忘了把file控件的透明的改為0。
?
posted on 2014-09-21 17:44 NET未來(lái)之路 閱讀(...) 評(píng)論(...) 編輯 收藏轉(zhuǎn)載于:https://www.cnblogs.com/lonelyxmas/p/3984766.html
總結(jié)
以上是生活随笔為你收集整理的利用iframe无刷新上传文件的坑的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: linux ps aux 结果解释
- 下一篇: 小知识汇总----不断更新中...