JavaScript 圖片預(yù)覽效果 推薦
兼容:ie6/7/8, firefox 3.5.5
后臺(tái)支持下還兼容:opera 10.10, safari 4.0.4, chrome 3.0

ps:兼容opera, safari和chrome需要后臺(tái)支持,請(qǐng)下載實(shí)例測(cè)試。
程序說明
【基本原理】
圖片預(yù)覽主要包括兩個(gè)部分:從file表單控件獲取圖像數(shù)據(jù),根據(jù)數(shù)據(jù)顯示預(yù)覽圖像。
程序的file和img屬性就是用來保存file控件和顯示預(yù)覽圖像的容器的,而img還必須是img元素。
程序有以下幾種預(yù)覽方式:
simple模式:直接從file的value獲取圖片路徑來顯示預(yù)覽,適用于ie6;
filter模式:通過selection獲取file的圖片路徑,再用濾鏡來顯示預(yù)覽,適用于ie7/8;
domfile模式:調(diào)用file的getAsDataURL方法獲取Data URI數(shù)據(jù)來顯示預(yù)覽,適用于ff3;
remote模式:最后的辦法,把file提交后臺(tái)處理后返回圖片數(shù)據(jù)來顯示預(yù)覽,全適用。
程序定義時(shí)就自動(dòng)根據(jù)瀏覽器設(shè)置MODE屬性:
$$B.firefox ? "domfile" :
$$B.opera || $$B.chrome || $$B.safari ? "remote" : "simple";
如果用能力檢測(cè)會(huì)比較麻煩,所以只用了瀏覽器檢測(cè)。
由于瀏覽器對(duì)應(yīng)的默認(rèn)模式是不會(huì)變的,這個(gè)值直接會(huì)保存到函數(shù)屬性中作為公用屬性。
ps:ie6也可以用filter模式,不過它有更好的simple模式。
【獲取數(shù)據(jù)】
調(diào)用preview方法,就會(huì)執(zhí)行預(yù)覽程序:
this._preview( this._getData() );
}
在通過檢測(cè)后,再調(diào)用_getData獲取數(shù)據(jù),并作為_preview的參數(shù)進(jìn)入預(yù)覽下一步。
程序初始化時(shí)就會(huì)根據(jù)mode來設(shè)置_getData數(shù)據(jù)獲取程序:
this._getData = this._getDataFun(opt.mode);
mode的默認(rèn)值是ImagePreview.MODE,也可以在可選參數(shù)中自定義。
由于兼容性問題,一般應(yīng)保留默認(rèn)值,除非是使用全兼容的remote模式。
在_getDataFun里面,根據(jù)mode返回?cái)?shù)據(jù)獲取程序:
case "filter" :
return this._filterData;
case "domfile" :
return this._domfileData;
case "remote" :
return this._remoteData;
case "simple" :
default :
return this._simpleData;
}
不同的模式有不同的數(shù)據(jù)獲取程序:
濾鏡數(shù)據(jù)獲取程序:
try{
return document.selection.createRange().text;
} finally { document.selection.empty(); }
一般用在ie7/8,在file控件select后再用selection對(duì)象獲得文件本地路徑。
此時(shí)file控件不能隱藏,否則不能被select,不過一般能選擇文件就肯定能被select了。
確實(shí)要隱藏也可以在獲取數(shù)據(jù)之后再隱藏。
domfile數(shù)據(jù)獲取程序:
用getAsDataURL從file控件獲取數(shù)據(jù),這個(gè)方法暫時(shí)只有ff3支持。
遠(yuǎn)程數(shù)據(jù)獲取程序:
this._upload && this._upload.upload();
用_upload上傳文件對(duì)象把數(shù)據(jù)提交后臺(tái),根據(jù)返回的數(shù)據(jù)再顯示。
這個(gè)方法不屬于本地預(yù)覽,是沒有辦法中的辦法。
一般數(shù)據(jù)獲取程序:
最原始的方法,現(xiàn)在只有ie6還支持從file的value直接獲取本地路徑。
獲取的數(shù)據(jù)作為參數(shù),在_preview預(yù)覽程序中進(jìn)行預(yù)覽:
this._data = data; this._show();
}
首先排除空值或相同值的情況,再執(zhí)行_show預(yù)覽顯示程序,其中_data屬性用來保存當(dāng)前的圖片數(shù)據(jù)。
圖片使用Data URI數(shù)據(jù)時(shí)可能會(huì)設(shè)置一個(gè)很大的src值,在ie8獲取很大的src值會(huì)出現(xiàn)“無效指針”的錯(cuò)誤。
使用_data屬性保存這個(gè)值可以避免從src獲取值而觸發(fā)這個(gè)錯(cuò)誤。
遠(yuǎn)程數(shù)據(jù)獲取程序沒有返回值,因?yàn)樗枰却祷財(cái)?shù)據(jù),在_preview中會(huì)自動(dòng)排除。
【顯示預(yù)覽】
程序初始化時(shí)就會(huì)根據(jù)mode來設(shè)置_show預(yù)覽顯示程序:
除了filter模式,都是使用_simpleShow顯示程序來顯示預(yù)覽圖片的。
里面會(huì)先調(diào)用_simplePreload方法設(shè)置一般預(yù)載圖片對(duì)象:
preload.onload = function(){ oThis._imgShow( oThis._data, this.width, this.height ); };
preload.onerror = function(){ oThis._error(); };
預(yù)載圖片對(duì)象保存在_preload屬性中,主要用來判斷圖像能否加載成功并獲取圖片原始尺寸。
要實(shí)現(xiàn)這些功能只要用Image對(duì)象就足夠了。
在onload中執(zhí)行_imgShow顯示預(yù)覽,在onerror中進(jìn)行出錯(cuò)處理。
ps:ff、chrome和safari的圖片對(duì)象還有naturalHeight和naturalWidth屬性可以獲取圖片的原始尺寸。
然后設(shè)置_preload的src預(yù)載圖片,如果成功預(yù)載就會(huì)執(zhí)行_imgShow顯示預(yù)覽。
要注意src的設(shè)置要在onload/onerror的設(shè)置之后,否則設(shè)置之前就加載完成的話就觸發(fā)不了事件了。
_imgShow需要三個(gè)參數(shù),包括要預(yù)覽圖片的src值,圖片原始寬度和圖片原始高度。
在_imgShow里面首先設(shè)置預(yù)覽圖片的尺寸:


ratio = Math.max( 0, this.ratio ) || Math.min( 1,
Math.max( 0, this.maxWidth ) / width || 1,
Math.max( 0, this.maxHeight ) / height || 1
);
style.width = Math.round( width * ratio ) + "px";
style.height = Math.round( height * ratio ) + "px";
這里的關(guān)鍵是獲取ratio比例值,如果自定義的ratio大于0就直接使用自定義的比例,否則就根據(jù)參數(shù)自動(dòng)計(jì)算。
自動(dòng)計(jì)算首先要確保maxWidth最大寬度和maxHeight最大高度大于等于0。
然后分別跟原始寬高做“/”運(yùn)算得到比例,如果比例為0表示不限制,那么比例就自動(dòng)改為1。
最后取比較小的比例來計(jì)算,程序設(shè)定了比例最大值為1,這樣就不會(huì)自動(dòng)放大圖片了。
當(dāng)然比例的計(jì)算可以根據(jù)需要自行修改。
ps:style的優(yōu)先級(jí)比屬性(width/height)高,所以要用style設(shè)置。
最后設(shè)置img的src就實(shí)現(xiàn)預(yù)覽了。
【remote模式】
remote模式會(huì)先提交file控件到后臺(tái),通過返回圖片數(shù)據(jù)來顯示圖片。
它跟其他模式最大的區(qū)別就是獲取數(shù)據(jù)的部分。
在_remoteData遠(yuǎn)程數(shù)據(jù)獲取程序中,會(huì)調(diào)用_setUpload來設(shè)置上傳文件對(duì)象。
如果設(shè)置了action,并存在QuickUpload函數(shù),就會(huì)進(jìn)行實(shí)例化一個(gè)上傳文件對(duì)象保存到_upload中:
this._upload = new QuickUpload(this.file, {
onReady: function(){
this.action = oThis.action; this.timeout = oThis.timeout;
var parameter = this.parameter;
parameter.ratio = oThis.ratio;
parameter.width = oThis.maxWidth;
parameter.height = oThis.maxHeight;
},
onFinish: function(iframe){
try{
oThis._preview( iframe.contentWindow.document.body.innerHTML );
}catch(e){ oThis._error("remote error"); }
},
onTimeout: function(){ oThis._error("timeout error"); }
});
這里使用的QuickUpload就是簡(jiǎn)便無刷新文件上傳程序。
在onReady中設(shè)置參數(shù),在onFinish中處理返回?cái)?shù)據(jù),onTimeout進(jìn)行出錯(cuò)處理。
返回的數(shù)據(jù)可以是圖片的地址或?qū)?yīng)Data URI數(shù)據(jù),然后給_preview處理。
當(dāng)然針對(duì)不同的后臺(tái)輸出,數(shù)據(jù)處理的方式也不同,可以按照需要修改。
后臺(tái)最好先根據(jù)傳遞的參數(shù)縮小圖片,盡量減少返回?cái)?shù)據(jù)來提高預(yù)覽速度。
【filter模式】
filter模式在_filterData程序中得到文件本地路徑,但ie7/8都不允許直接使用本地路徑顯示圖片。
不過還是可以通過濾鏡,用本地路徑來做預(yù)覽圖片效果。
filter模式使用_filterShow方法來顯示預(yù)覽圖片。
里面先調(diào)用_filterPreload方法來設(shè)置濾鏡預(yù)載圖片對(duì)象。
跟一般預(yù)載圖片對(duì)象不同,濾鏡預(yù)載對(duì)象是用濾鏡來顯示圖片,所以并不一定要圖像元素。
程序就使用了div元素作為濾鏡預(yù)載對(duì)象:
$$D.setStyle( preload, {
width: "1px", height: "1px",
visibility: "hidden", position: "absolute", left: "-9999px", top: "-9999px",
filter: "progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod='image')"
});
var body = document.body; body.insertBefore( preload, body.childNodes[0] );
在樣式設(shè)置中隱藏元素并添加濾鏡,要使濾鏡生效width和height必須設(shè)置一個(gè)值。
由于要獲取尺寸,只能用visibility來隱藏并插入body,關(guān)于AlphaImageLoader濾鏡后面再介紹。
然后在_filterShow中預(yù)載圖片:
preload.filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = data;
}catch(e){ this._error("filter error"); return; }
成功的話,再給img載入圖片:
最后調(diào)用_imgShow設(shè)置尺寸:
由于img是一個(gè)圖片對(duì)象,默認(rèn)會(huì)顯示一個(gè)小圖標(biāo),為了去掉這個(gè)小圖標(biāo),可以讓它顯示一個(gè)透明圖片。
程序傳遞了ImagePreview.TRANSPARENT來設(shè)置透明圖片,具體數(shù)據(jù)在Data URI 和 MHTML再說明。
ps:當(dāng)然也可以在filter模式用div做預(yù)覽圖片對(duì)象就沒有小圖標(biāo)了,但這樣兼容起來會(huì)麻煩很多。
【AlphaImageLoader濾鏡】
filter模式使用的是AlphaImageLoader濾鏡。
它的作用是在對(duì)象容器邊界內(nèi),在對(duì)象的背景和內(nèi)容之間顯示一張圖片。
如果載入的是png圖片,其透明度會(huì)被支持,可以用來解決png的兼容問題。
詳細(xì)參考msdn的AlphaImageLoader Filter和“Microsoft.AlphaImageLoader濾鏡講解”。
它包括三個(gè)屬性:enabled(濾鏡是否激活),sizingMethod(圖像顯示方式)和src(圖像路徑)。
程序主要使用后面兩個(gè)屬性。
sizingMethod有三種方式:
crop:剪切圖片以適應(yīng)對(duì)象尺寸;
image:默認(rèn)值。增大或減小對(duì)象的尺寸邊界以適應(yīng)圖片的尺寸;
scale:縮放圖片以適應(yīng)對(duì)象的尺寸邊界。
對(duì)于預(yù)載圖片對(duì)象_preload,要獲取圖片的原始尺寸,所以要用image方式。
而預(yù)覽圖片對(duì)象img,則要根據(jù)設(shè)定尺寸顯示圖片,所以要用scale方式。
而src屬性的路徑還支持本地路徑,是實(shí)現(xiàn)filter模式的關(guān)鍵所在。
幸運(yùn)的是濾鏡并沒有像file控件那樣提高安全性,否則就沒辦法實(shí)現(xiàn)圖片本地預(yù)覽了。
【nsIDOMFile接口】
ff從3.0(或更早)開始,就不能通過value獲取file的完整路徑,也不支持直接用本地路徑顯示圖片。
不過欣喜的是,它同時(shí)也提供了nsIDOMFile接口,能更好地獲取文件數(shù)據(jù)。
在ff的file控件有一個(gè)FileList對(duì)象,包含了帶nsIDOMFile接口的File對(duì)象。
ps:FileList對(duì)象貌似是一個(gè)NodeList對(duì)象,但目前只能用第一個(gè),可能是為了將來實(shí)現(xiàn)一個(gè)file控件選擇多個(gè)文件的功能預(yù)留的。
這個(gè)File對(duì)象有三個(gè)獲取文件數(shù)據(jù)的方法:
getAsText:獲取文件的文本數(shù)據(jù),可以通過參數(shù)設(shè)置編碼;
getAsDataURL:獲取文件的Data URI數(shù)據(jù);
getAsBinary:獲取文件的二進(jìn)制數(shù)據(jù)。
其中g(shù)etAsDataURL獲得的Data URI數(shù)據(jù)可以用于顯示圖片,_domfileData中就是用它來獲取數(shù)據(jù)的。
File對(duì)象還有支持兩個(gè)屬性:fileName(文件名,不包括路徑)和fileSize(文件大?。?。
相關(guān)具體說明參考mozilla的File和nsIDOMFile。
【Data URI 和 MHTML】
上面已經(jīng)多次提到Data URI,詳細(xì)介紹請(qǐng)看秦歌的“Data URI 和 MHTML”。
Data URI的主要作用是以字符代替數(shù)據(jù),從而把文件“嵌”在代碼里。
除了ie,其他瀏覽器基本都很好的支持了Data URI。
ie8也有限度地支持,詳細(xì)參考msdn的data Protocol。
由于opera,safari和chrome需要remote模式的瀏覽器都支持Data URI,所以程序返回的是Data URI形式的數(shù)據(jù)。
相比返回路徑的方法,返回Data URI不需要?jiǎng)?chuàng)建文件,還少一次HTTP請(qǐng)求。
ps:ie8只支持32k的Data URI數(shù)據(jù),在ie8使用時(shí)要注意數(shù)據(jù)大小。
在filter模式需要一個(gè)透明圖片來去掉img默認(rèn)顯示的小圖標(biāo),一般的方法需要一個(gè)圖片文件。
為了“省下”這個(gè)文件,可以使用Data URI來做一個(gè)1*1的透明圖片:
支持Data URI的情況下,只要把img的src設(shè)置為這個(gè)值就可以顯示一個(gè)透明圖片了。
雖然ie6/7不支持Data URI,還可以用mhtml來代替。
在ImagePreviewd.js開頭有一段注釋了的代碼:


--_CLOUDGAMER
Content-Location:blankImage
Content-Transfer-Encoding:base64
R0lGODlhAQABAJEAAAAAAP///////wAAACH5BAEAAAIALAAAAAABAAEAAAICVAEAOw==
這是mhtml記錄數(shù)據(jù)的形式,調(diào)用時(shí)要按以下格式設(shè)置img的src:
mhtml:文件完整路徑!blankImage
其中blankImage表示要獲取的數(shù)據(jù)在文件對(duì)應(yīng)的Content-Location。
問題在于如何獲得script(js文件)的完整路徑(包含http開頭的路徑)。
首先要在腳本運(yùn)行時(shí)獲取,當(dāng)前運(yùn)行的script肯定是document.scripts的最后一個(gè):
document.scripts[document.scripts.length - 1]
ps:document.scripts詳細(xì)參考msdn的scripts Collection,ff不支持,可以用getElementsByTagName("script")兼容。
接著可以利用getAttribute從src獲取script的完整路徑:
ie6/7的getAttribute支持第二個(gè)參數(shù),設(shè)為4表示返回完整路徑的url地址,詳細(xì)參考msdn的getAttribute Method。
結(jié)合Data URI 和 MHTML可以這樣得到透明圖片數(shù)據(jù):
"mhtml:" + document.scripts[document.scripts.length - 1].getAttribute("src", 4) + "!blankImage" :
"data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==";
使用時(shí)要注意:
腳本必須單獨(dú)另存為一個(gè)文件,作為mhtml需要的文件路徑。
要自動(dòng)獲取完整路徑需要用script標(biāo)簽鏈接文件。
【超空間】
程序還有一個(gè)dispose方法用于銷毀程序。
包括這幾個(gè)部分:
_upload上傳文件對(duì)象:它本身已經(jīng)有一個(gè)dispose方法來銷毀程序;
_preload預(yù)載圖片對(duì)象:先清除它的onload/onerror事件再移除元素;
file和img屬性:直接設(shè)為null,由于不是程序創(chuàng)建的元素,留給使用者來移除。
說到移除元素,順便說一下超空間(DOM hyperspace),這是從“ppk談javascript”中看到的。
大概指的是當(dāng)元素不在dom里面,而js又有關(guān)聯(lián)時(shí),元素并不會(huì)消失,而是保存在一個(gè)稱為“超空間”的地方。
詳細(xì)參考書的DOM 超空間部分。
書中還說可以根據(jù)是否有parentNode來判斷元素是否在超空間,但測(cè)試以下代碼:
<script>
var elm = document.createElement("div");
alert(elm.parentNode);
document.body.removeChild(document.body.appendChild(elm));
alert(elm.parentNode);
</script>
第一次parentNode都是null,沒有問題,按理第二次也應(yīng)該是null,但ie卻是一個(gè)object。
經(jīng)測(cè)試,這個(gè)object的nodeType是11,也就是一個(gè)碎片對(duì)象(FRAGMENT)。
而且各個(gè)被removeChild移除的元素的parentNode都不相同,即會(huì)生成不同的碎片對(duì)象。
這種情況算不算在“超空間”呢,不過書中也只是說“一般來說”,也不用太考究。
那么用innerHTML清除呢?再測(cè)試以下代碼:
<script>
var elm = document.getElementById("test");
document.body.innerHTML = "";
alert(elm.parentNode);
</script>
結(jié)果在ie也是null了,看來removeChild和innerHTML在清除元素時(shí)產(chǎn)生了不同的結(jié)果。
那個(gè)碎片對(duì)象貌似沒什么用(難道為了保證有parentNode?),那是不是innerHTML就一定比removeChild好呢?
再測(cè)試以下代碼:
<style>div{border:1px solid #000; height:20px;}</style>
<span><div id="test1">test1</div></span>
<span><div id="test2">test2</div></span>
</body>
<script>
var div1 = document.getElementById("test1"), parent1 = div1.parentNode;
parent1.removeChild(div1);
alert(div1.tagName + ":" + div1.innerHTML);
parent1.appendChild(div1);
var div2 = document.getElementById("test2"), parent2 = div2.parentNode;
parent2.innerHTML = "";
alert(div2.tagName + ":" + div2.innerHTML);
parent2.appendChild(div2);
</script>
當(dāng)使用removeChild時(shí),移除元素的結(jié)構(gòu)并沒有發(fā)生變化,各個(gè)瀏覽器的效果都一樣。
而使用innerHTML清除時(shí),其他瀏覽器的效果跟removeChild一樣,但在ie被移除的元素就只剩下一個(gè)“外殼”了。
個(gè)人推測(cè),ie在使用innerHTML時(shí),被移除的元素會(huì)變成一個(gè)個(gè)單獨(dú)的元素,失去了彼此的聯(lián)系。
形象點(diǎn)說就是removeChild是直接掰斷樹枝,還能繼續(xù)嫁接使用,而innerHTML是把需要的樹葉節(jié)點(diǎn)取下來,再把樹枝燒掉。
ps:僅僅是推測(cè),誰有官方資料請(qǐng)告訴我。
那么removeChild的好處是移除的元素能再次使用,兼容性好,不好的地方是ie會(huì)產(chǎn)生一個(gè)沒用的碎片對(duì)象。
而innerHTML的好處是不會(huì)產(chǎn)生多余的碎片對(duì)象,方便高效,但在ie被移除的元素基本不能再用,有兼容性問題。
那就可以根據(jù)需要使用不同的方法了,至于防止內(nèi)存泄漏用那個(gè)好,感覺是innerHTML,但沒有更深入研究的話還說不清楚。
使用技巧
一般來preview方法都是在onchange中調(diào)用,即選擇文件后立即顯示預(yù)覽。
在不需要程序時(shí)最好執(zhí)行一次dispose方法來銷毀程序,防止內(nèi)存泄漏等。
利用ImagePreview.TRANSPARENT可以顯示透明圖片,而不需另外隱藏或增加文件。
第二個(gè)實(shí)例中的ResetFile是用來重置file控件的,詳細(xì)參考這里file的reset。
而file控件樣式設(shè)置詳細(xì)參考這里的file樣式。
asp版本使用Persits.Jpeg組件縮放圖片,測(cè)試請(qǐng)先安裝該組件。
使用說明
實(shí)例化時(shí),有兩個(gè)必要參數(shù),分別是file控件對(duì)象和img元素的預(yù)覽顯示對(duì)象:
可選參數(shù)用來設(shè)置系統(tǒng)的默認(rèn)屬性,包括:
屬性: 默認(rèn)值//說明
mode: ImagePreview.MODE,//預(yù)覽模式
ratio: 0,//自定義比例
maxWidth: 0,//縮略圖寬度
maxHeight: 0,//縮略圖高度
onCheck: function(){},//預(yù)覽檢測(cè)時(shí)執(zhí)行
onShow: function(){},//預(yù)覽圖片時(shí)執(zhí)行
onErr: function(){},//預(yù)覽錯(cuò)誤時(shí)執(zhí)行
以下在remote模式時(shí)有效
action: undefined,//設(shè)置action
timeout: 0//設(shè)置超時(shí)(0為不設(shè)置)
如果要使用remote模式必須設(shè)置一個(gè)action。
還提供了以下方法:
preview:執(zhí)行預(yù)覽操作;
dispose:銷毀程序。
程序源碼
this.file = $$(file);//文件對(duì)象
this.img = $$(img);//預(yù)覽圖片對(duì)象
this._preload = null;//預(yù)載圖片對(duì)象
this._data = "";//圖像數(shù)據(jù)
this._upload = null;//remote模式使用的上傳文件對(duì)象
var opt = this._setOptions(options);
this.action = opt.action;
this.timeout = opt.timeout;
this.ratio = opt.ratio;
this.maxWidth = opt.maxWidth;
this.maxHeight = opt.maxHeight;
this.onCheck = opt.onCheck;
this.onShow = opt.onShow;
this.onErr = opt.onErr;
//設(shè)置數(shù)據(jù)獲取程序
this._getData = this._getDataFun(opt.mode);
//設(shè)置預(yù)覽顯示程序
this._show = opt.mode !== "filter" ? this._simpleShow : this._filterShow;
};
//根據(jù)瀏覽器獲取模式
ImagePreview.MODE = $$B.ie7 || $$B.ie8 ? "filter" :
$$B.firefox ? "domfile" :
$$B.opera || $$B.chrome || $$B.safari ? "remote" : "simple";
//透明圖片
ImagePreview.TRANSPARENT = $$B.ie7 || $$B.ie6 ?
"mhtml:" + document.scripts[document.scripts.length - 1].getAttribute("src", 4) + "!blankImage" :
"data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==";
ImagePreview.prototype = {
//設(shè)置默認(rèn)屬性
_setOptions: function(options) {
this.options = {//默認(rèn)值
mode: ImagePreview.MODE,//預(yù)覽模式
ratio: 0,//自定義比例
maxWidth: 0,//縮略圖寬度
maxHeight: 0,//縮略圖高度
onCheck: function(){},//預(yù)覽檢測(cè)時(shí)執(zhí)行
onShow: function(){},//預(yù)覽圖片時(shí)執(zhí)行
onErr: function(){},//預(yù)覽錯(cuò)誤時(shí)執(zhí)行
//以下在remote模式時(shí)有效
action: undefined,//設(shè)置action
timeout: 0//設(shè)置超時(shí)(0為不設(shè)置)
};
return $$.extend(this.options, options || {});
},
//開始預(yù)覽
preview: function() {
if ( this.file && false !== this.onCheck() ) {
this._preview( this._getData() );
}
},
//根據(jù)mode返回?cái)?shù)據(jù)獲取程序
_getDataFun: function(mode) {
switch (mode) {
case "filter" :
return this._filterData;
case "domfile" :
return this._domfileData;
case "remote" :
return this._remoteData;
case "simple" :
default :
return this._simpleData;
}
},
//濾鏡數(shù)據(jù)獲取程序
_filterData: function() {
this.file.select();
try{
return document.selection.createRange().text;
} finally { document.selection.empty(); }
},
//domfile數(shù)據(jù)獲取程序
_domfileData: function() {
return this.file.files[0].getAsDataURL();
},
//遠(yuǎn)程數(shù)據(jù)獲取程序
_remoteData: function() {
this._setUpload();
this._upload && this._upload.upload();
},
//一般數(shù)據(jù)獲取程序
_simpleData: function() {
return this.file.value;
},
//設(shè)置remote模式的上傳文件對(duì)象
_setUpload: function() {
if ( !this._upload && this.action !== undefined && typeof QuickUpload === "function" ) {
var oThis = this;
this._upload = new QuickUpload(this.file, {
onReady: function(){
this.action = oThis.action; this.timeout = oThis.timeout;
var parameter = this.parameter;
parameter.ratio = oThis.ratio;
parameter.width = oThis.maxWidth;
parameter.height = oThis.maxHeight;
},
onFinish: function(iframe){
try{
oThis._preview( iframe.contentWindow.document.body.innerHTML );
}catch(e){ oThis._error("remote error"); }
},
onTimeout: function(){ oThis._error("timeout error"); }
});
}
},
//預(yù)覽程序
_preview: function(data) {
//空值或相同的值不執(zhí)行顯示
if ( !!data && data !== this._data ) {
this._data = data; this._show();
}
},
//設(shè)置一般預(yù)載圖片對(duì)象
_simplePreload: function() {
if ( !this._preload ) {
var preload = this._preload = new Image(), oThis = this;
preload.onload = function(){ oThis._imgShow( oThis._data, this.width, this.height ); };
preload.onerror = function(){ oThis._error(); };
}
},
//一般顯示
_simpleShow: function() {
this._simplePreload();
this._preload.src = this._data;
},
//設(shè)置濾鏡預(yù)載圖片對(duì)象
_filterPreload: function() {
if ( !this._preload ) {
var preload = this._preload = document.createElement("div");
//隱藏并設(shè)置濾鏡
$$D.setStyle( preload, {
width: "1px", height: "1px",
visibility: "hidden", position: "absolute", left: "-9999px", top: "-9999px",
filter: "progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod='image')"
});
//插入body
var body = document.body; body.insertBefore( preload, body.childNodes[0] );
}
},
//濾鏡顯示
_filterShow: function() {
this._filterPreload();
var preload = this._preload, data = this._data;
try{
preload.filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = data;
}catch(e){ this._error("filter error"); return; }
//設(shè)置濾鏡并顯示
this.img.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod='scale',src='" + data + "')";
this._imgShow( ImagePreview.TRANSPARENT, preload.offsetWidth, preload.offsetHeight );
},
//顯示預(yù)覽
_imgShow: function(src, width, height) {
var img = this.img, style = img.style,
ratio = Math.max( 0, this.ratio ) || Math.min( 1,
Math.max( 0, this.maxWidth ) / width || 1,
Math.max( 0, this.maxHeight ) / height || 1
);
//設(shè)置預(yù)覽尺寸
style.width = Math.round( width * ratio ) + "px";
style.height = Math.round( height * ratio ) + "px";
//設(shè)置src
img.src = src;
this.onShow();
},
//銷毀程序
dispose: function() {
//銷毀上傳文件對(duì)象
if ( this._upload ) {
this._upload.dispose(); this._upload = null;
}
//銷毀預(yù)載圖片對(duì)象
if ( this._preload ) {
var preload = this._preload, parent = preload.parentNode;
this._preload = preload.onload = preload.onerror = null;
parent && parent.removeChild(preload);
}
//銷毀相關(guān)對(duì)象
this.file = this.img = null;
},
//出錯(cuò)
_error: function(err) {
this.onErr(err);
}
}
完整實(shí)例下載(asp與asp.net)
this.ratio = opt.ratio;
this.maxWidth = opt.maxWidth;
this.maxHeight = opt.maxHeight;
this.onCheck = opt.onCheck;
this.onShow = opt.onShow;
this.onErr = opt.onErr;
//設(shè)置數(shù)據(jù)獲取程序
this._getData = this._getDataFun(opt.mode);
//設(shè)置預(yù)覽顯示程序
this._show = opt.mode !== "filter" ? this._simpleShow : this._filterShow;
};
//根據(jù)瀏覽器獲取模式
ImagePreview.MODE = $$B.ie7 || $$B.ie8 ? "filter" :
$$B.firefox ? "domfile" :
$$B.opera || $$B.chrome || $$B.safari ? "remote" : "simple";
//透明圖片
ImagePreview.TRANSPARENT = $$B.ie7 || $$B.ie6 ?
"mhtml:" + document.scripts[document.scripts.length - 1].getAttribute("src", 4) + "!blankImage" :
"data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==";
ImagePreview.prototype = {
//設(shè)置默認(rèn)屬性
_setOptions: function(options) {
this.options = {//默認(rèn)值
mode: ImagePreview.MODE,//預(yù)覽模式
ratio: 0,//自定義比例
maxWidth: 0,//縮略圖寬度
maxHeight: 0,//縮略圖高度
onCheck: function(){},//預(yù)覽檢測(cè)時(shí)執(zhí)行
onShow: function(){},//預(yù)覽圖片時(shí)執(zhí)行
onErr: function(){},//預(yù)覽錯(cuò)誤時(shí)執(zhí)行
//以下在remote模式時(shí)有效
action: undefined,//設(shè)置action
timeout: 0//設(shè)置超時(shí)(0為不設(shè)置)
};
return $$.extend(this.options, options || {});
},
//開始預(yù)覽
preview: function() {
if ( this.file && false !== this.onCheck() ) {
this._preview( this._getData() );
}
},
//根據(jù)mode返回?cái)?shù)據(jù)獲取程序
_getDataFun: function(mode) {
switch (mode) {
case "filter" :
return this._filterData;
case "domfile" :
return this._domfileData;
case "remote" :
return this._remoteData;
case "simple" :
default :
return this._simpleData;
}
},
//濾鏡數(shù)據(jù)獲取程序
_filterData: function() {
this.file.select();
try{
return document.selection.createRange().text;
} finally { document.selection.empty(); }
},
//domfile數(shù)據(jù)獲取程序
_domfileData: function() {
return this.file.files[0].getAsDataURL();
},
//遠(yuǎn)程數(shù)據(jù)獲取程序
_remoteData: function() {
this._setUpload();
this._upload && this._upload.upload();
},
//一般數(shù)據(jù)獲取程序
_simpleData: function() {
return this.file.value;
},
//設(shè)置remote模式的上傳文件對(duì)象
_setUpload: function() {
if ( !this._upload && this.action !== undefined && typeof QuickUpload === "function" ) {
var oThis = this;
this._upload = new QuickUpload(this.file, {
onReady: function(){
this.action = oThis.action; this.timeout = oThis.timeout;
var parameter = this.parameter;
parameter.ratio = oThis.ratio;
parameter.width = oThis.maxWidth;
parameter.height = oThis.maxHeight;
},
onFinish: function(iframe){
try{
oThis._preview( iframe.contentWindow.document.body.innerHTML );
}catch(e){ oThis._error("remote error"); }
},
onTimeout: function(){ oThis._error("timeout error"); }
});
}
},
//預(yù)覽程序
_preview: function(data) {
//空值或相同的值不執(zhí)行顯示
if ( !!data && data !== this._data ) {
this._data = data; this._show();
}
},
//設(shè)置一般預(yù)載圖片對(duì)象
_simplePreload: function() {
if ( !this._preload ) {
var preload = this._preload = new Image(), oThis = this;
preload.onload = function(){ oThis._imgShow( oThis._data, this.width, this.height ); };
preload.onerror = function(){ oThis._error(); };
}
},
//一般顯示
_simpleShow: function() {
this._simplePreload();
this._preload.src = this._data;
},
//設(shè)置濾鏡預(yù)載圖片對(duì)象
_filterPreload: function() {
if ( !this._preload ) {
var preload = this._preload = document.createElement("div");
//隱藏并設(shè)置濾鏡
$$D.setStyle( preload, {
width: "1px", height: "1px",
visibility: "hidden", position: "absolute", left: "-9999px", top: "-9999px",
filter: "progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod='image')"
});
//插入body
var body = document.body; body.insertBefore( preload, body.childNodes[0] );
}
},
//濾鏡顯示
_filterShow: function() {
this._filterPreload();
var preload = this._preload, data = this._data;
try{
preload.filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = data;
}catch(e){ this._error("filter error"); return; }
//設(shè)置濾鏡并顯示
this.img.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod='scale',src='" + data + "')";
this._imgShow( ImagePreview.TRANSPARENT, preload.offsetWidth, preload.offsetHeight );
},
//顯示預(yù)覽
_imgShow: function(src, width, height) {
var img = this.img, style = img.style,
ratio = Math.max( 0, this.ratio ) || Math.min( 1,
Math.max( 0, this.maxWidth ) / width || 1,
Math.max( 0, this.maxHeight ) / height || 1
);
//設(shè)置預(yù)覽尺寸
style.width = Math.round( width * ratio ) + "px";
style.height = Math.round( height * ratio ) + "px";
//設(shè)置src
img.src = src;
this.onShow();
},
//銷毀程序
dispose: function() {
//銷毀上傳文件對(duì)象
if ( this._upload ) {
this._upload.dispose(); this._upload = null;
}
//銷毀預(yù)載圖片對(duì)象
if ( this._preload ) {
var preload = this._preload, parent = preload.parentNode;
this._preload = preload.onload = preload.onerror = null;
parent && parent.removeChild(preload);
}
//銷毀相關(guān)對(duì)象
this.file = this.img = null;
},
//出錯(cuò)
_error: function(err) {
this.onErr(err);
}
}
完整實(shí)例下載(asp與asp.net)