JavaScript 圖片上傳預覽效果
當前位置:點晴教程→知識管理交流
→『 技術文檔交流 』
[p]圖片上傳預覽是一種在圖片上傳之前對圖片進行本地預覽的技術。[br]使用戶選擇圖片后能立即查看圖片,而不需上傳服務器,提高用戶體驗。[br]但隨著瀏覽器安全性的提高,要實現圖片上傳預覽也越來越困難。[br]不過群眾的智慧是無限的,網上已經有很多變通或先進的方法來實現。[br]例如ie7/ie8的濾鏡預覽法,firefox 3的getasdataurl方法。[br]但在opera、safari和chrome還是沒有辦法實現本地預覽,只能通過后臺來支持預覽。[br]在研究了各種預覽方法后,作為總結,寫了這個程序,跟大家一起分享。[br]上次寫的[url=http://cnblogs.com/cloudgamer/archive/2009/12/01/quick_upload.html][color=#3366cc]簡便無刷新文件上傳系統[/color][/url]最初的目的就是用來實現這個圖片預覽效果的。[br]兼容:ie6/7/8, firefox 3.5.5[br]后臺支持下還兼容:opera 10.10, safari 4.0.4, chrome 3.0[/p]
[p][br][b]效果預覽[/b][/p] .perview {width:600px;background:#fff; border-collapse:collapse;} .perview td, .perview th {padding:5px;border:1px solid #ccc;} .perview th {background-color:#f0f0f0; height:20px;} .perview a:link, .perview a:visited, .perview a:hover, .perview a:active {color:#00f;} .perview table{ width:100%;border-collapse:collapse;} 選擇文件 預覽圖 [br] /*file樣式*/ #idpicfile { width:80px;height:20px;overflow:hidden;position:relative; background:url(http://images.cnblogs.com/cnblogs_com/cloudgamer/169629/o_addfile.jpg) center no-repeat; } #idpicfile input { font-size:20px;cursor:pointer; position:absolute;right:0;bottom:0; filter:alpha(opacity=0);opacity:0; outline:none;hide-focus:expression(this.hidefocus=true); } 選擇圖片: 文件路徑 預覽圖 操作 [url=#]移除[/url] [url=#]移除[/url] [p][br]ps:兼容opera, safari和chrome需要后臺支持,請下載實例測試。[/p] [p][br][b]程序說明[/b][/p] [p][b]【基本原理】[/b][/p] [p]圖片預覽主要包括兩個部分:從file表單控件獲取圖像數據,根據數據顯示預覽圖像。[br]程序的file和img屬性就是用來保存file控件和顯示預覽圖像的容器的,而img還必須是img元素。[/p] [p]程序有以下幾種預覽方式:[br]simple模式:直接從file的value獲取圖片路徑來顯示預覽,適用于ie6;[br]filter模式:通過selection獲取file的圖片路徑,再用濾鏡來顯示預覽,適用于ie7/8;[br]domfile模式:調用file的getasdataurl方法獲取data uri數據來顯示預覽,適用于ff3;[br]remote模式:最后的辦法,把file提交后臺處理后返回圖片數據來顯示預覽,全適用。[/p] [p]程序定義時就自動根據瀏覽器設置mode屬性:[br][/p] [color=#000000]imagepreview.mode [/color][color=#000000]=[/color][color=#000000] $$b.ie7 [/color][color=#000000]||[/color][color=#000000] $$b.ie8 [/color][color=#000000]?[/color][color=#000000] [/color][color=#000000]"[/color][color=#000000]filter[/color][color=#000000]"[/color][color=#000000] :[br] $$b.firefox [/color][color=#000000]?[/color][color=#000000] [/color][color=#000000]"[/color][color=#000000]domfile[/color][color=#000000]"[/color][color=#000000] :[br] $$b.opera [/color][color=#000000]||[/color][color=#000000] $$b.chrome [/color][color=#000000]||[/color][color=#000000] $$b.safari [/color][color=#000000]?[/color][color=#000000] [/color][color=#000000]"[/color][color=#000000]remote[/color][color=#000000]"[/color][color=#000000] : [/color][color=#000000]"[/color][color=#000000]simple[/color][color=#000000]"[/color][color=#000000];[/color] [p][br]如果用能力檢測會比較麻煩,所以只用了瀏覽器檢測。[br]由于瀏覽器對應的默認模式是不會變的,這個值會保存到函數屬性中作為公用屬性。[br]ps:ie6也可以用filter模式,不過它有更好的simple模式。[/p] [p][br][b]【獲取數據】[/b][/p] [p]調用preview方法,就會執行預覽程序:[/p] [color=#0000ff]if[/color][color=#000000] ( [/color][color=#0000ff]this[/color][color=#000000].file [/color][color=#000000]&&[/color][color=#000000] [/color][color=#0000ff]false[/color][color=#000000] [/color][color=#000000]!==[/color][color=#000000] [/color][color=#0000ff]this[/color][color=#000000].oncheck() ) {[br] [/color][color=#0000ff]this[/color][color=#000000]._preview( [/color][color=#0000ff]this[/color][color=#000000]._getdata() );[br]}[/color] [p][br]在通過檢測后,再調用_getdata獲取數據,并作為_preview的參數進入下一步。[/p] [p]程序初始化時就會根據mode來設置_getdata數據獲取程序:[br][/p] [color=#0000ff]this[/color][color=#000000]._getdata [/color][color=#000000]=[/color][color=#000000] [/color][color=#0000ff]this[/color][color=#000000]._getdatafun(opt.mode);[/color] [p][br]mode的默認值是imagepreview.mode,也可以在可選參數中自定義。 [br]由于兼容性問題,一般應保留默認值,除非是使用全兼容的remote模式。[/p] [p]在_getdatafun里面,根據mode返回數據獲取程序:[/p] [img]http://images.cnblogs.com/outliningindicators/contractedblock.gif[/img][img]http://images.cnblogs.com/outliningindicators/expandedblockstart.gif[/img]代碼 [color=#0000ff]switch[/color][color=#000000] (mode) {[br] [/color][color=#0000ff]case[/color][color=#000000] [/color][color=#000000]"[/color][color=#000000]filter[/color][color=#000000]"[/color][color=#000000] :[br] [/color][color=#0000ff]return[/color][color=#000000] [/color][color=#0000ff]this[/color][color=#000000]._filterdata;[br] [/color][color=#0000ff]case[/color][color=#000000] [/color][color=#000000]"[/color][color=#000000]domfile[/color][color=#000000]"[/color][color=#000000] :[br] [/color][color=#0000ff]return[/color][color=#000000] [/color][color=#0000ff]this[/color][color=#000000]._domfiledata;[br] [/color][color=#0000ff]case[/color][color=#000000] [/color][color=#000000]"[/color][color=#000000]remote[/color][color=#000000]"[/color][color=#000000] :[br] [/color][color=#0000ff]return[/color][color=#000000] [/color][color=#0000ff]this[/color][color=#000000]._remotedata;[br] [/color][color=#0000ff]case[/color][color=#000000] [/color][color=#000000]"[/color][color=#000000]simple[/color][color=#000000]"[/color][color=#000000] :[br] [/color][color=#0000ff]default[/color][color=#000000] :[br] [/color][color=#0000ff]return[/color][color=#000000] [/color][color=#0000ff]this[/color][color=#000000]._simpledata;[br]}[/color] [p][br]不同的模式有不同的數據獲取程序:[br]濾鏡數據獲取程序:[/p] [color=#0000ff]this[/color][color=#000000].file.select();[br][/color][color=#0000ff]try[/color][color=#000000]{[br] [/color][color=#0000ff]return[/color][color=#000000] document.selection.createrange().text;[br]} [/color][color=#0000ff]finally[/color][color=#000000] { document.selection.empty(); }[/color] [p]一般用在ie7/8,在file控件select后再通過selection對象獲得文件本地路徑。[br]此時file控件不能隱藏,否則不能被select,不過一般能選擇文件就肯定能被select了。[br]確實要隱藏也可以在獲取數據之后再隱藏。[/p] [p]domfile數據獲取程序:[/p] [color=#0000ff]return[/color][color=#000000] [/color][color=#0000ff]this[/color][color=#000000].file.files[[/color][color=#000000]0[/color][color=#000000]].getasdataurl();[/color] [p]用getasdataurl從file控件獲取數據,這個方法暫時只有ff3支持。[/p] [p]遠程數據獲取程序:[/p] [color=#0000ff]this[/color][color=#000000]._setupload();[br][/color][color=#0000ff]this[/color][color=#000000]._upload [/color][color=#000000]&&[/color][color=#000000] [/color][color=#0000ff]this[/color][color=#000000]._upload.upload();[/color] [p]用_upload上傳文件對象把數據提交后臺,根據返回的數據再顯示。[br]這個方法不屬于本地預覽,是沒有辦法中的辦法。[/p] [p]一般數據獲取程序:[/p] [color=#0000ff]return[/color][color=#000000] [/color][color=#0000ff]this[/color][color=#000000].file.value;[/color] [p]最原始的方法,現在只有ie6還支持從file的value直接獲取本地路徑。[/p] [p]獲取數據后,作為_preview預覽程序的參數,再進行處理:[/p] [color=#0000ff]if[/color][color=#000000] ( [/color][color=#000000]!![/color][color=#000000]data [/color][color=#000000]&&[/color][color=#000000] data [/color][color=#000000]!==[/color][color=#000000] [/color][color=#0000ff]this[/color][color=#000000]._data ) {[br] [/color][color=#0000ff]this[/color][color=#000000]._data [/color][color=#000000]=[/color][color=#000000] data; [/color][color=#0000ff]this[/color][color=#000000]._show();[br]}[/color] [p][br]首先排除空值或相同值的情況,再執行_show程序進行顯示預覽,其中_data屬性用來保存當前的圖片數據。[br]圖片使用data uri數據時可能會設置一個很大的src值,在ie8獲取很大的src值會出現“無效指針”的錯誤。[br]使用_data屬性保存這個值可以避免從src取值而觸發這個錯誤。[/p] [p]遠程數據獲取程序沒有返回值,因為它需要等待返回數據,在_preview中會自動排除。[/p] [p][br][b]【顯示預覽】[/b][/p] [p]程序初始化時就會根據mode來設置_show預覽顯示程序:[/p] [color=#0000ff]this[/color][color=#000000]._show [/color][color=#000000]=[/color][color=#000000] opt.mode [/color][color=#000000]!==[/color][color=#000000] [/color][color=#000000]"[/color][color=#000000]filter[/color][color=#000000]"[/color][color=#000000] [/color][color=#000000]?[/color][color=#000000] [/color][color=#0000ff]this[/color][color=#000000]._simpleshow : [/color][color=#0000ff]this[/color][color=#000000]._filtershow;[/color] [p][br]除了filter模式,都是使用_simpleshow顯示程序來顯示預覽圖片的。[br]里面會先調用_simplepreload方法設置一般預載圖片對象:[/p] [img]http://images.cnblogs.com/outliningindicators/contractedblock.gif[/img][img]http://images.cnblogs.com/outliningindicators/expandedblockstart.gif[/img]代碼 [color=#0000ff]if[/color][color=#000000] ( [/color][color=#000000]![/color][color=#0000ff]this[/color][color=#000000]._preload ) {[br] [/color][color=#0000ff]var[/color][color=#000000] preload [/color][color=#000000]=[/color][color=#000000] [/color][color=#0000ff]this[/color][color=#000000]._preload [/color][color=#000000]=[/color][color=#000000] [/color][color=#0000ff]new[/color][color=#000000] image(), othis [/color][color=#000000]=[/color][color=#000000] [/color][color=#0000ff]this[/color][color=#000000],[br] onload [/color][color=#000000]=[/color][color=#000000] [/color][color=#0000ff]function[/color][color=#000000](){ othis._imgshow( othis._data, [/color][color=#0000ff]this[/color][color=#000000].width, [/color][color=#0000ff]this[/color][color=#000000].height ); };[br] [/color][color=#0000ff]this[/color][color=#000000]._onload [/color][color=#000000]=[/color][color=#000000] [/color][color=#0000ff]function[/color][color=#000000](){ [/color][color=#0000ff]this[/color][color=#000000].onload [/color][color=#000000]=[/color][color=#000000] [/color][color=#0000ff]null[/color][color=#000000]; onload.call([/color][color=#0000ff]this[/color][color=#000000]); }[br] preload.onload [/color][color=#000000]=[/color][color=#000000] $$b.ie [/color][color=#000000]?[/color][color=#000000] [/color][color=#0000ff]this[/color][color=#000000]._onload : onload;[br] preload.onerror [/color][color=#000000]=[/color][color=#000000] [/color][color=#0000ff]function[/color][color=#000000](){ othis._error(); };[br]} [/color][color=#0000ff]else[/color][color=#000000] [/color][color=#0000ff]if[/color][color=#000000] ( $$b.ie ) {[br] [/color][color=#0000ff]this[/color][color=#000000]._preload.onload [/color][color=#000000]=[/color][color=#000000] [/color][color=#0000ff]this[/color][color=#000000]._onload;[br]}[/color] [p][br]預載圖片對象保存在_preload屬性中,主要用來判斷圖像能否加載成功并獲取圖片原始尺寸。[br]要實現這些功能使用image對象就足夠了。[br]在onload中執行_imgshow顯示預覽,在onerror中進行出錯處理。[br]ps:ff、chrome和safari的圖片對象還有naturalheight和naturalwidth屬性可以獲取圖片的原始尺寸,即使圖片尺寸已經修改過。 [/p] [p]這里要注意ie6/7的gif圖片載入bug,測試以下代碼:[br][/p] [img]http://images.cnblogs.com/outliningindicators/contractedblock.gif[/img][img]http://images.cnblogs.com/outliningindicators/expandedblockstart.gif[/img]代碼 [color=#000000]<[/color][color=#000000]body[/color][color=#000000]><[/color][color=#000000]img id[/color][color=#000000]=[/color][color=#000000]"[/color][color=#000000]img[/color][color=#000000]"[/color][color=#000000] [/color][color=#000000]/[/color][color=#000000]> <[/color][color=#000000]/[/color][color=#000000]div[/color][color=#000000]><[/color][color=#000000]/[/color][color=#000000]body>[/color][color=#000000][br][/color][color=#000000]<[/color][color=#000000]script[/color][color=#000000]>[/color][color=#000000][br]img.onload [/color][color=#000000]=[/color][color=#000000] [/color][color=#0000ff]function[/color][color=#000000](){ div.innerhtml [/color][color=#000000]+=[/color][color=#000000] [/color][color=#0000ff]this[/color][color=#000000].complete [/color][color=#000000]+[/color][color=#000000] [/color][color=#000000]"[/color][color=#000000], [/color][color=#000000]"[/color][color=#000000]; };[br]img.src [/color][color=#000000]=[/color][color=#000000] [/color][color=#000000]"[/color][color=#000000]http://tuan.pcpop.com/image/my/loading.gif[/color][color=#000000]"[/color][color=#000000];[br][/color][color=#000000]<[/color][color=#000000]/[/color][color=#000000]script>[/color]
[p][br]一般圖片執行一次onload后并不會重復執行,但ie6/7的gif每次循環播放都會執行一次onload。[br]ps:ie8在非標準(怪辟)模式下也有相同的問題。[br]可以在onload的時候,判斷complete是否為false來判斷是否重復加載。[br]ps:除了ie,其他瀏覽器在onload時complete就已經為true了。[br]問題是選擇另一個圖片時這個complete仍然是true,這樣就沒有意義了。[br]所以只好在onload里面重置onload為null,并在每次選擇文件重設onload了。[/p] [p]然后設置_preload的src預載圖片,如果成功預載就會執行_imgshow顯示預覽。[br]要注意src的設置要在onload/onerror的設置之后,否則設置之前就加載完成的話就觸發不了事件了。[/p] [p]_imgshow需要三個參數,包括要預覽圖片的src值,圖片原始寬度和圖片原始高度。[br]在_imgshow里面首先設置預覽圖片的尺寸:[br][/p] [img]http://images.cnblogs.com/outliningindicators/contractedblock.gif[/img][img]http://images.cnblogs.com/outliningindicators/expandedblockstart.gif[/img]代碼 [color=#0000ff]var[/color][color=#000000] img [/color][color=#000000]=[/color][color=#000000] [/color][color=#0000ff]this[/color][color=#000000].img, style [/color][color=#000000]=[/color][color=#000000] img.style,[br] ratio [/color][color=#000000]=[/color][color=#000000] math.max( [/color][color=#000000]0[/color][color=#000000], [/color][color=#0000ff]this[/color][color=#000000].ratio ) [/color][color=#000000]||[/color][color=#000000] math.min( [/color][color=#000000]1[/color][color=#000000],[br] math.max( [/color][color=#000000]0[/color][color=#000000], [/color][color=#0000ff]this[/color][color=#000000].maxwidth ) [/color][color=#000000]/[/color][color=#000000] width [/color][color=#000000]||[/color][color=#000000] [/color][color=#000000]1[/color][color=#000000],[br] math.max( [/color][color=#000000]0[/color][color=#000000], [/color][color=#0000ff]this[/color][color=#000000].maxheight ) [/color][color=#000000]/[/color][color=#000000] height [/color][color=#000000]||[/color][color=#000000] [/color][color=#000000]1[/color][color=#000000][br] );[br] [br]style.width [/color][color=#000000]=[/color][color=#000000] math.round( width [/color][color=#000000]*[/color][color=#000000] ratio ) [/color][color=#000000]+[/color][color=#000000] [/color][color=#000000]"[/color][color=#000000]px[/color][color=#000000]"[/color][color=#000000];[br]style.height [/color][color=#000000]=[/color][color=#000000] math.round( height [/color][color=#000000]*[/color][color=#000000] ratio ) [/color][color=#000000]+[/color][color=#000000] [/color][color=#000000]"[/color][color=#000000]px[/color][color=#000000]"[/color][color=#000000];[/color] [p][br]這里的關鍵是獲取ratio比例值,如果自定義的ratio大于0就直接使用自定義的比例,否則就根據參數自動計算。[br]自動計算首先要確保maxwidth最大寬度和maxheight最大高度大于等于0。[br]然后分別跟原始寬高做“/”運算得到比例,如果比例為0表示不限制,那么比例就自動改為1。[br]最后取比較小的比例來計算,程序設定了比例最大值為1,這樣就不會自動放大圖片了。[br]當然比例的計算可以根據需要自行修改。[br]ps:style的優先級比屬性(width/height)高,所以要用style設置。[/p] [p]最后設置img的src就可以實現預覽了。[/p] [p][br][b]【remote模式】[/b][/p] [p]remote模式會先提交file控件到后臺,通過返回的數據來顯示圖片。[br]它跟其他模式最大的區別就是獲取數據的部分。[/p] [p]在_remotedata遠程數據獲取程序中,會調用_setupload來設置上傳文件對象。[br]如果設置了action,并存在quickupload函數,就會實例化一個上傳文件對象保存到_upload中:[/p] [img]http://images.cnblogs.com/outliningindicators/contractedblock.gif[/img][img]http://images.cnblogs.com/outliningindicators/expandedblockstart.gif[/img]代碼 [color=#0000ff]var[/color][color=#000000] othis [/color][color=#000000]=[/color][color=#000000] [/color][color=#0000ff]this[/color][color=#000000];[br][/color][color=#0000ff]this[/color][color=#000000]._upload [/color][color=#000000]=[/color][color=#000000] [/color][color=#0000ff]new[/color][color=#000000] quickupload([/color][color=#0000ff]this[/color][color=#000000].file, {[br] onready: [/color][color=#0000ff]function[/color][color=#000000](){[br] [/color][color=#0000ff]this[/color][color=#000000].action [/color] 該文章在 2010/5/1 2:56:21 編輯過 |
關鍵字查詢
相關文章
正在查詢... |