JavaScript 圖片上傳預(yù)覽效果
當(dāng)前位置:點(diǎn)晴教程→知識(shí)管理交流
→『 技術(shù)文檔交流 』
[p]圖片上傳預(yù)覽是一種在圖片上傳之前對(duì)圖片進(jìn)行本地預(yù)覽的技術(shù)。[br]使用戶(hù)選擇圖片后能立即查看圖片,而不需上傳服務(wù)器,提高用戶(hù)體驗(yàn)。[br]但隨著瀏覽器安全性的提高,要實(shí)現(xiàn)圖片上傳預(yù)覽也越來(lái)越困難。[br]不過(guò)群眾的智慧是無(wú)限的,網(wǎng)上已經(jīng)有很多變通或先進(jìn)的方法來(lái)實(shí)現(xiàn)。[br]例如ie7/ie8的濾鏡預(yù)覽法,firefox 3的getasdataurl方法。[br]但在opera、safari和chrome還是沒(méi)有辦法實(shí)現(xiàn)本地預(yù)覽,只能通過(guò)后臺(tái)來(lái)支持預(yù)覽。[br]在研究了各種預(yù)覽方法后,作為總結(jié),寫(xiě)了這個(gè)程序,跟大家一起分享。[br]上次寫(xiě)的[url=http://cnblogs.com/cloudgamer/archive/2009/12/01/quick_upload.html][color=#3366cc]簡(jiǎn)便無(wú)刷新文件上傳系統(tǒng)[/color][/url]最初的目的就是用來(lái)實(shí)現(xiàn)這個(gè)圖片預(yù)覽效果的。[br]兼容:ie6/7/8, firefox 3.5.5[br]后臺(tái)支持下還兼容:opera 10.10, safari 4.0.4, chrome 3.0[/p]
[p][br][b]效果預(yù)覽[/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;} 選擇文件 預(yù)覽圖 [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); } 選擇圖片: 文件路徑 預(yù)覽圖 操作 [url=#]移除[/url] [url=#]移除[/url] [p][br]ps:兼容opera, safari和chrome需要后臺(tái)支持,請(qǐng)下載實(shí)例測(cè)試。[/p] [p][br][b]程序說(shuō)明[/b][/p] [p][b]【基本原理】[/b][/p] [p]圖片預(yù)覽主要包括兩個(gè)部分:從file表單控件獲取圖像數(shù)據(jù),根據(jù)數(shù)據(jù)顯示預(yù)覽圖像。[br]程序的file和img屬性就是用來(lái)保存file控件和顯示預(yù)覽圖像的容器的,而img還必須是img元素。[/p] [p]程序有以下幾種預(yù)覽方式:[br]simple模式:直接從file的value獲取圖片路徑來(lái)顯示預(yù)覽,適用于ie6;[br]filter模式:通過(guò)selection獲取file的圖片路徑,再用濾鏡來(lái)顯示預(yù)覽,適用于ie7/8;[br]domfile模式:調(diào)用file的getasdataurl方法獲取data uri數(shù)據(jù)來(lái)顯示預(yù)覽,適用于ff3;[br]remote模式:最后的辦法,把file提交后臺(tái)處理后返回圖片數(shù)據(jù)來(lái)顯示預(yù)覽,全適用。[/p] [p]程序定義時(shí)就自動(dòng)根據(jù)瀏覽器設(shè)置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]如果用能力檢測(cè)會(huì)比較麻煩,所以只用了瀏覽器檢測(cè)。[br]由于瀏覽器對(duì)應(yīng)的默認(rèn)模式是不會(huì)變的,這個(gè)值會(huì)保存到函數(shù)屬性中作為公用屬性。[br]ps:ie6也可以用filter模式,不過(guò)它有更好的simple模式。[/p] [p][br][b]【獲取數(shù)據(jù)】[/b][/p] [p]調(diào)用preview方法,就會(huì)執(zhí)行預(yù)覽程序:[/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]在通過(guò)檢測(cè)后,再調(diào)用_getdata獲取數(shù)據(jù),并作為_(kāi)preview的參數(shù)進(jìn)入下一步。[/p] [p]程序初始化時(shí)就會(huì)根據(jù)mode來(lái)設(shè)置_getdata數(shù)據(jù)獲取程序:[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的默認(rèn)值是imagepreview.mode,也可以在可選參數(shù)中自定義。 [br]由于兼容性問(wèn)題,一般應(yīng)保留默認(rèn)值,除非是使用全兼容的remote模式。[/p] [p]在_getdatafun里面,根據(jù)mode返回?cái)?shù)據(jù)獲取程序:[/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]不同的模式有不同的數(shù)據(jù)獲取程序:[br]濾鏡數(shù)據(jù)獲取程序:[/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后再通過(guò)selection對(duì)象獲得文件本地路徑。[br]此時(shí)file控件不能隱藏,否則不能被select,不過(guò)一般能選擇文件就肯定能被select了。[br]確實(shí)要隱藏也可以在獲取數(shù)據(jù)之后再隱藏。[/p] [p]domfile數(shù)據(jù)獲取程序:[/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控件獲取數(shù)據(jù),這個(gè)方法暫時(shí)只有ff3支持。[/p] [p]遠(yuǎn)程數(shù)據(jù)獲取程序:[/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上傳文件對(duì)象把數(shù)據(jù)提交后臺(tái),根據(jù)返回的數(shù)據(jù)再顯示。[br]這個(gè)方法不屬于本地預(yù)覽,是沒(méi)有辦法中的辦法。[/p] [p]一般數(shù)據(jù)獲取程序:[/p] [color=#0000ff]return[/color][color=#000000] [/color][color=#0000ff]this[/color][color=#000000].file.value;[/color] [p]最原始的方法,現(xiàn)在只有ie6還支持從file的value直接獲取本地路徑。[/p] [p]獲取數(shù)據(jù)后,作為_(kāi)preview預(yù)覽程序的參數(shù),再進(jìn)行處理:[/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]首先排除空值或相同值的情況,再執(zhí)行_show程序進(jìn)行顯示預(yù)覽,其中_data屬性用來(lái)保存當(dāng)前的圖片數(shù)據(jù)。[br]圖片使用data uri數(shù)據(jù)時(shí)可能會(huì)設(shè)置一個(gè)很大的src值,在ie8獲取很大的src值會(huì)出現(xiàn)“無(wú)效指針”的錯(cuò)誤。[br]使用_data屬性保存這個(gè)值可以避免從src取值而觸發(fā)這個(gè)錯(cuò)誤。[/p] [p]遠(yuǎn)程數(shù)據(jù)獲取程序沒(méi)有返回值,因?yàn)樗枰却祷財(cái)?shù)據(jù),在_preview中會(huì)自動(dòng)排除。[/p] [p][br][b]【顯示預(yù)覽】[/b][/p] [p]程序初始化時(shí)就會(huì)根據(jù)mode來(lái)設(shè)置_show預(yù)覽顯示程序:[/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顯示程序來(lái)顯示預(yù)覽圖片的。[br]里面會(huì)先調(diào)用_simplepreload方法設(shè)置一般預(yù)載圖片對(duì)象:[/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]預(yù)載圖片對(duì)象保存在_preload屬性中,主要用來(lái)判斷圖像能否加載成功并獲取圖片原始尺寸。[br]要實(shí)現(xiàn)這些功能使用image對(duì)象就足夠了。[br]在onload中執(zhí)行_imgshow顯示預(yù)覽,在onerror中進(jìn)行出錯(cuò)處理。[br]ps:ff、chrome和safari的圖片對(duì)象還有naturalheight和naturalwidth屬性可以獲取圖片的原始尺寸,即使圖片尺寸已經(jīng)修改過(guò)。 [/p] [p]這里要注意ie6/7的gif圖片載入bug,測(cè)試以下代碼:[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]一般圖片執(zhí)行一次onload后并不會(huì)重復(fù)執(zhí)行,但ie6/7的gif每次循環(huán)播放都會(huì)執(zhí)行一次onload。[br]ps:ie8在非標(biāo)準(zhǔn)(怪辟)模式下也有相同的問(wèn)題。[br]可以在onload的時(shí)候,判斷complete是否為false來(lái)判斷是否重復(fù)加載。[br]ps:除了ie,其他瀏覽器在onload時(shí)complete就已經(jīng)為true了。[br]問(wèn)題是選擇另一個(gè)圖片時(shí)這個(gè)complete仍然是true,這樣就沒(méi)有意義了。[br]所以只好在onload里面重置onload為null,并在每次選擇文件重設(shè)onload了。[/p] [p]然后設(shè)置_preload的src預(yù)載圖片,如果成功預(yù)載就會(huì)執(zhí)行_imgshow顯示預(yù)覽。[br]要注意src的設(shè)置要在onload/onerror的設(shè)置之后,否則設(shè)置之前就加載完成的話(huà)就觸發(fā)不了事件了。[/p] [p]_imgshow需要三個(gè)參數(shù),包括要預(yù)覽圖片的src值,圖片原始寬度和圖片原始高度。[br]在_imgshow里面首先設(shè)置預(yù)覽圖片的尺寸:[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]這里的關(guān)鍵是獲取ratio比例值,如果自定義的ratio大于0就直接使用自定義的比例,否則就根據(jù)參數(shù)自動(dòng)計(jì)算。[br]自動(dòng)計(jì)算首先要確保maxwidth最大寬度和maxheight最大高度大于等于0。[br]然后分別跟原始寬高做“/”運(yùn)算得到比例,如果比例為0表示不限制,那么比例就自動(dòng)改為1。[br]最后取比較小的比例來(lái)計(jì)算,程序設(shè)定了比例最大值為1,這樣就不會(huì)自動(dòng)放大圖片了。[br]當(dāng)然比例的計(jì)算可以根據(jù)需要自行修改。[br]ps:style的優(yōu)先級(jí)比屬性(width/height)高,所以要用style設(shè)置。[/p] [p]最后設(shè)置img的src就可以實(shí)現(xiàn)預(yù)覽了。[/p] [p][br][b]【remote模式】[/b][/p] [p]remote模式會(huì)先提交file控件到后臺(tái),通過(guò)返回的數(shù)據(jù)來(lái)顯示圖片。[br]它跟其他模式最大的區(qū)別就是獲取數(shù)據(jù)的部分。[/p] [p]在_remotedata遠(yuǎn)程數(shù)據(jù)獲取程序中,會(huì)調(diào)用_setupload來(lái)設(shè)置上傳文件對(duì)象。[br]如果設(shè)置了action,并存在quickupload函數(shù),就會(huì)實(shí)例化一個(gè)上傳文件對(duì)象保存到_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 編輯過(guò) |
關(guān)鍵字查詢(xún)
相關(guān)文章
正在查詢(xún)... |