随着浏覽器安全性的提高,要實作圖檔預覽也越來越困難。
不過群衆的智慧是無限的,網上也有很多變通或先進的方法來實作。
在研究了各種預覽方法後,作為總結,寫了這個程式,跟大家一起分享。
上次寫的簡便無重新整理檔案上傳系統最初的目的就是用來實作這個圖檔預覽效果。
相容:ie6/7/8, firefox 3.5.5
背景支援下還相容:opera 10.10, safari 4.0.4, chrome 3.0
ps:相容opera, safari和chrome需要背景支援,請下載下傳執行個體測試。
程式說明
【基本原理】
圖檔預覽主要包括兩個部分:從file表單控件擷取圖像資料,根據資料顯示預覽圖像。
程式的file和img屬性就是用來儲存file控件和顯示預覽圖像的容器的,而img還必須是img元素。
程式有以下幾種預覽方式:
simple模式:直接從file的value擷取圖檔路徑來顯示預覽,适用于ie6;
filter模式:通過selection擷取file的圖檔路徑,再用濾鏡來顯示預覽,适用于ie7/8;
domfile模式:調用file的getAsDataURL方法擷取Data URI資料來顯示預覽,适用于ff3;
remote模式:最後的辦法,把file送出背景處理後傳回圖檔資料來顯示預覽,全适用。
程式定義時就自動根據浏覽器設定MODE屬性:
ImagePreview.MODE = $$B.ie7 || $$B.ie8 ? " filter " :
$$B.firefox ? " domfile " :
$$B.opera || $$B.chrome || $$B.safari ? " remote " : " simple " ;
如果用能力檢測會比較麻煩,是以隻用了浏覽器檢測。
由于浏覽器對應的預設模式是不會變的,這個值會儲存到函數屬性中作為公用屬性。
ps:ie6也可以用filter模式,不過它有更好的simple模式。
【擷取資料】
調用preview方法,就會執行預覽程式:
if ( this .file && false !== this .onCheck() ) {
this ._preview( this ._getData() );
}
在通過檢測後,再調用_getData擷取資料,并作為_preview的參數進入下一步。
程式初始化時就會根據mode來設定_getData資料擷取程式:
this ._getData = this ._getDataFun(opt.mode);
mode的預設值是ImagePreview.MODE,也可以在可選參數中自定義。
由于相容性問題,一般應保留預設值,除非是使用全相容的remote模式。
在_getDataFun裡面,根據mode傳回資料擷取程式:
代碼 switch (mode) {
case " filter " :
return this ._filterData;
case " domfile " :
return this ._domfileData;
case " remote " :
return this ._remoteData;
case " simple " :
default :
return this ._simpleData;
}
不同的模式有不同的資料擷取程式:
濾鏡資料擷取程式:
this .file.select();
try {
return document.selection.createRange().text;
} finally { document.selection.empty(); }
一般用在ie7/8,在file控件select後再通過selection對象獲得檔案本地路徑。
此時file控件不能隐藏,否則不能被select,不過一般能選擇檔案就肯定能被select了。
确實要隐藏也可以在擷取資料之後再隐藏。
domfile資料擷取程式:
return this .file.files[ 0 ].getAsDataURL();
用getAsDataURL從file控件擷取資料,這個方法暫時隻有ff3支援。
遠端資料擷取程式:
this ._setUpload();
this ._upload && this ._upload.upload();
用_upload上傳檔案對象把資料送出背景,根據傳回的資料再顯示。
這個方法不屬于本地預覽,是沒有辦法中的辦法。
一般資料擷取程式:
return this .file.value;
最原始的方法,現在隻有ie6還支援從file的value直接擷取本地路徑。
擷取資料後,作為_preview預覽程式的參數,再進行處理:
if ( !! data && data !== this ._data ) {
this ._data = data; this ._show();
}
首先排除空值或相同值的情況,再執行_show程式進行顯示預覽,其中_data屬性用來儲存目前的圖檔資料。
圖檔使用Data URI資料時可能會設定一個很大的src值,在ie8擷取很大的src值會出現“無效指針”的錯誤。
使用_data屬性儲存這個值可以避免從src取值而觸發這個錯誤。
遠端資料擷取程式沒有傳回值,因為它需要等待傳回資料,在_preview中會自動排除。
【顯示預覽】
程式初始化時就會根據mode來設定_show預覽顯示程式:
this ._show = opt.mode !== " filter " ? this ._simpleShow : this ._filterShow;
除了filter模式,都是使用_simpleShow顯示程式來顯示預覽圖檔的。
裡面會先調用_simplePreload方法設定一般預載圖檔對象:
var preload = this ._preload = new Image(), oThis = this ;
preload.onload = function (){ oThis._imgShow( oThis._data, this .width, this .height ); };
preload.onerror = function (){ oThis._error(); };
預載圖檔對象儲存在_preload屬性中,主要用來判斷圖像能否加載成功并擷取圖檔原始尺寸。
要實作這些功能使用Image對象就足夠了。
在onload中執行_imgShow顯示預覽,在onerror中進行出錯處理。
ps:ff、chrome和safari的圖檔對象還有naturalHeight和naturalWidth屬性可以擷取圖檔的原始尺寸,即使圖檔尺寸已經修改過。
然後設定_preload的src預載圖檔,如果成功預載就會執行_imgShow顯示預覽。
要注意src的設定要在onload/onerror的設定之後,否則設定之前就加載完成的話就觸發不了事件了。
_imgShow需要三個參數,包括要預覽圖檔的src值,圖檔原始寬度和圖檔原始高度。
在_imgShow裡面首先設定預覽圖檔的尺寸:
代碼 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
);
style.width = Math.round( width * ratio ) + " px " ;
style.height = Math.round( height * ratio ) + " px " ;
這裡的關鍵是擷取ratio比例值,如果自定義的ratio大于0就直接使用自定義的比例,否則就根據參數自動計算。
自動計算首先要確定maxWidth最大寬度和maxHeight最大高度大于等于0。
然後分别跟原始寬高做“/”運算得到比例,如果比例為0表示不限制,那麼比例就自動改為1。
最後取比較小的比例來計算,程式設定了比例最大值為1,這樣就不會自動放大圖檔了。
當然比例的計算可以根據需要自行修改。
ps:style的優先級比屬性(width/height)高,是以要用style設定。
最後設定img的src就可以實作預覽了。
【remote模式】
remote模式會先送出file控件到背景,通過傳回的資料來顯示圖檔。
它跟其他模式最大的差別就是擷取資料的部分。
在_remoteData遠端資料擷取程式中,會調用_setUpload來設定上傳檔案對象。
如果設定了action,并存在QuickUpload函數,就會執行個體化一個上傳檔案對象儲存到_upload中:
代碼 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 " ); }
});
這裡使用的QuickUpload就是簡便無重新整理檔案上傳程式。
在onReady中設定參數,在onFinish中處理傳回資料,onTimeout進行出錯處理。
傳回的資料可以是圖檔的位址或對應的Data URI資料,然後給_preview處理。
當然針對不同的背景輸出,資料處理的方式也不同,可以按照需要修改。
背景最好先根據傳遞的參數縮小圖檔,盡量減少傳回資料來提高預覽速度。
【filter模式】
filter模式在_filterData程式中得到檔案本地路徑,但ie7/8都不允許直接使用本地路徑顯示圖檔。
不過還是可以通過濾鏡,用本地路徑來做預覽圖檔效果。
filter模式使用_filterShow方法來顯示預覽圖檔。
裡面先調用_filterPreload方法來設定濾鏡預載圖檔對象。
跟一般預載圖檔對象不同,濾鏡預載對象是用濾鏡來顯示圖檔,是以并不一定要圖像元素。
程式就使用了div元素作為濾鏡預載對象:
代碼 var preload = this ._preload = document.createElement( " div " );
$$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 ] );
在樣式設定中隐藏元素并添加濾鏡,要使濾鏡生效width和height必須設定一個值。
由于要擷取尺寸,隻能用visibility來隐藏并插入body,關于AlphaImageLoader濾鏡後面再介紹。
然後在_filterShow中預載圖檔:
try {
preload.filters.item( " DXImageTransform.Microsoft.AlphaImageLoader " ).src = data;
} catch (e){ this ._error( " filter error " ); return ; }
成功的話,再給img載入圖檔:
this .img.style.filter = " progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod='scale',src=/ "" +
data.replace(/[)' " ] / g, function(s){ return escape(s) }) + "/")";
注意,如果路徑中有“)”,“'”這類字元的話直接拼接到濾鏡字元串中會出現類似sql注入的問題。
是以程式會對這些字元進行escape替換。
ps:雖然單引号和雙引号這裡并不是必要,還是一起替換掉安心點。
而預載對象由于是直接設定濾鏡的src屬性,不會産生拼接字問題。
那為什麼img不使用這個方法呢?
因為濾鏡所在元素插入文檔之前,雖然能通過style設定filter,但并不能通過filters.item擷取濾鏡對象。
在不能確定元素是否在文檔裡面的情況下,隻能通過style來設定filter了。
最後調用_imgShow設定尺寸:
this ._imgShow( ImagePreview.TRANSPARENT, preload.offsetWidth, preload.offsetHeight );
由于img是一個圖檔對象,預設會顯示一個小圖示,為了去掉這個小圖示,可以讓它顯示一個透明圖檔。
程式傳遞了ImagePreview.TRANSPARENT來設定透明圖檔,具體資料在Data URI 和 MHTML再說明。
ps:當然也可以在filter模式用div做預覽圖檔對象就沒有小圖示了,但這樣相容起來會麻煩很多。
【AlphaImageLoader濾鏡】
filter模式使用的是AlphaImageLoader濾鏡。
它的作用是在對象容器邊界内,在對象的背景和内容之間顯示一張圖檔。
如果載入的是png圖檔,其透明度會被支援,是以它更多地用來解決png的相容問題。
詳細參考msdn的AlphaImageLoader Filter和“Microsoft.AlphaImageLoader濾鏡講解”。
它包括三個屬性:enabled(濾鏡是否激活),sizingMethod(圖像顯示方式)和src(圖像路徑)。
程式主要使用後面兩個屬性。
sizingMethod有三種方式:
crop:剪切圖檔以适應對象尺寸;
image:預設值。增大或減小對象的尺寸邊界以适應圖檔的尺寸;
scale:縮放圖檔以适應對象的尺寸邊界。
預載圖檔對象_preload,需要擷取圖檔的原始尺寸,是以要用image方式。
而預覽圖檔對象img,則要按設定尺寸顯示圖檔,是以要用scale方式。
而src屬性設定的路徑還支援本地路徑,是實作filter模式的關鍵所在。
還好濾鏡并沒有像file控件那樣提高安全性,否則ie7/8就沒有辦法實作本地預覽了。
【nsIDOMFile接口】
ff從3.0(或許更早)開始,就不能通過file控件的value屬性擷取檔案本地路徑,也不支援直接用本地路徑顯示圖檔。
不過欣喜的是,它同時也提供了nsIDOMFile接口,能更好地擷取檔案資料。
在ff的file控件有一個FileList對象,包含了帶nsIDOMFile接口的File對象。
ps:FileList對象貌似是一個NodeList集合,但目前隻能用第一個,可能是為了将來實作一個file控件選擇多個檔案的功能預留的。
這個File對象有三個擷取檔案資料的方法:
getAsText:擷取檔案的文本資料,可以通過參數設定編碼;
getAsDataURL:擷取檔案的Data URI(URL?)資料;
getAsBinary:擷取檔案的二進制資料。
其中getAsDataURL獲得的Data URI資料可以用于顯示圖檔,_domfileData中就是用它來擷取資料的。
File對象還支援兩個屬性:fileName(檔案名,不包括路徑)和fileSize(檔案大小)。
相關具體說明參考mozilla的File和nsIDOMFile。
【Data URI 和 MHTML】
上面已經多次提到Data URI,詳細介紹請看秦歌的“Data URI 和 MHTML”。
Data URI的主要作用是以字元代替資料,進而把檔案“嵌”在代碼裡。
除了ie,其他浏覽器基本都很好的支援了Data URI。
ie8也有限度地支援,詳細參考msdn的data Protocol。
由于opera,safari和chrome需要remote模式的浏覽器都支援Data URI,是以程式傳回的是Data URI形式的資料。
相比傳回路徑的方法,傳回Data URI不需要建立檔案,還少一次HTTP請求。
ps:ie8隻支援32k的Data URI資料,在ie8使用時要注意資料大小。
在filter模式需要一個透明圖檔來去掉img預設顯示的小圖示,一般的方法需要一個圖檔檔案。
為了“省下”這個檔案,可以使用Data URI來做一個1*1的透明圖檔:
data:image / gif;base64,R0lGODlhAQABAIAAAP / // wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==
支援Data URI的情況下,隻要把img的src設定為這個值就可以顯示一個透明圖檔了。
雖然ie6/7不支援Data URI,但還有mhtml可以使。
在ImagePreviewd.js開頭有一段注釋了的代碼:
代碼 Content - Type: multipart / related; boundary="_CLOUDGAMER"
-- _CLOUDGAMER
Content - Location:blankImage
Content - Transfer - Encoding:base64
R0lGODlhAQABAJEAAAAAAP // /wAAACH5BAEAAAIALAAAAAABAAEAAAICVAEAOw==
其中boundary的值是分隔符辨別,說明用于分隔資料段的字元。
Content-Location說明關聯引用位置,可以用作資料段的辨別。
Content-Transfer-Encoding就是字元編碼形式。
後面的代碼就是1*1的透明圖檔的base64編碼資料。
然後在代碼中這樣調用(例如設定img元素的src屬性):
mhtml:檔案完整路徑!blankImage
就可以連結到一個透明圖檔了。
接着就要解決如何獲得script(js檔案)的完整路徑(包含http開頭的路徑)的問題了。
首先要在腳本運作時擷取,目前運作的script肯定是document.scripts的最後一個:
document.scripts[document.scripts.length - 1 ]
ps:ff不支援document.scripts,可以用getElementsByTagName("script")來相容。
接着可以利用getAttribute從src擷取script的完整路徑:
document.scripts[document.scripts.length - 1 ].getAttribute( " src " , 4 )
ie6/7的getAttribute支援第二個參數,設為4表示傳回完整路徑的url位址,詳細參考msdn的getAttribute Method。
結合Data URI 和 MHTML可以這樣得到透明圖檔資料:
ImagePreview.TRANSPARENT = $$B.ie7 || $$B.ie6 ?
" mhtml: " + document.scripts[document.scripts.length - 1 ].getAttribute( " src " , 4 ) + " !blankImage " :
" data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw== " ;
使用時要注意:
腳本必須單獨另存為一個檔案,作為mhtml需要的檔案路徑。
要自動擷取完整路徑需要用script标簽連結檔案。
【超空間】
程式還有一個dispose方法用于銷毀程式。
包括這幾個部分:
_upload上傳檔案對象:它本身已經有一個dispose方法來銷毀程式;
_preload預載圖檔對象:先清除它的onload/onerror事件再移除元素;
file和img屬性:直接設為null,由于不是程式建立的元素,留給使用者來移除。
說到移除元素,順便說一下超空間(DOM hyperspace),這是從“ppk談javascript”中看到的。
大概指的是當元素不在dom裡面,而js又有關聯時,元素并不會消失,而是儲存在一個稱為“超空間”的地方。
詳細參考書的DOM 超空間部分。
書中還說可以根據是否有parentNode來判斷元素是否在超空間,但測試以下代碼:
< body >< / body>
< script >
var elm = document.createElement( " div " );
alert(elm.parentNode);
document.body.removeChild(document.body.appendChild(elm));
alert(elm.parentNode);
< / script>
第一次parentNode都是null,沒有問題,按理第二次也應該是null,但ie卻是一個object。
經測試,這個object的nodeType是11,也就是一個碎片對象(FRAGMENT)。
而且各個被removeChild移除的元素的parentNode都不相同,即會生成不同的碎片對象。
這種情況算不算在“超空間”呢,不過書中也隻是說“一般來說”,也不用太考究。
那麼用innerHTML清除呢?再測試以下代碼:
< body >< div id = " test " >< / div>< / body >
< script >
var elm = document.getElementById( " test " );
document.body.innerHTML = "" ;
alert(elm.parentNode);
< / script>
結果在ie也是null了,看來removeChild和innerHTML在清除元素時産生了不同的結果。
那個碎片對象貌似沒什麼用(難道為了保證有parentNode?),那是不是innerHTML就一定比removeChild好呢?
再測試以下代碼:
代碼 < body >
< 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>
當使用removeChild時,移除元素的結構并沒有發生變化,各個浏覽器的效果都一樣。
而使用innerHTML清除時,其他浏覽器的效果跟removeChild一樣,但在ie被移除的元素就隻剩下一個“外殼”了。
個人推測,ie在使用innerHTML時,被移除的元素會變成一個個單獨的元素,失去了彼此的聯系。
形象點說就是removeChild是直接掰斷樹枝,還能繼續嫁接使用,而innerHTML是把需要的樹葉節點取下來,再把樹枝燒掉。
ps:僅僅是推測,誰有官方資料請告訴我。
那麼removeChild的好處是移除的元素能再次使用,相容性好,不好的地方是ie會産生一個沒用的碎片對象。
而innerHTML的好處是不會産生多餘的碎片對象,友善高效,但在ie被移除的元素基本不能再用,有相容性問題。
那就可以根據需要使用不同的方法了,至于防止記憶體洩漏用那個好,感覺是innerHTML,但沒有更深入研究的話還說不清楚。
使用技巧
一般來preview方法都是在onchange中調用,即選擇檔案後立即顯示預覽。
在不需要程式時最好執行一次dispose方法來銷毀程式,防止記憶體洩漏等。
利用ImagePreview.TRANSPARENT可以顯示透明圖檔,而不需另外隐藏或增加檔案。
第二個執行個體中的ResetFile是用來重置file控件的,詳細參考這裡file的reset。
而file控件樣式設定詳細參考這裡的file樣式。
asp版本使用Persits.Jpeg元件縮放圖檔,測試請先安裝該元件。
使用說明
執行個體化時,有兩個必要參數,分别是file控件對象和img元素的預覽顯示對象:
new ImagePreview( file, img );
可選參數用來設定系統的預設屬性,包括:
屬性: 預設值//說明
mode: ImagePreview.MODE,//預覽模式
ratio: 0,//自定義比例
maxWidth: 0,//縮略圖寬度
maxHeight: 0,//縮略圖高度
onCheck: function(){},//預覽檢測時執行
onShow: function(){},//預覽圖檔時執行
onErr: function(){},//預覽錯誤時執行
以下在remote模式時有效
action: undefined,//設定action
timeout: 0//設定逾時(0為不設定)
如果要使用remote模式必須設定一個action。
還提供了以下方法:
preview:執行預覽操作;
dispose:銷毀程式。
程式源碼
代碼 var ImagePreview = function (file, img, options) {
this .file = $$(file); // 檔案對象
this .img = $$(img); // 預覽圖檔對象
this ._preload = null ; // 預載圖檔對象
this ._data = "" ; // 圖像資料
this ._upload = null ; // remote模式使用的上傳檔案對象
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;
// 設定資料擷取程式
this ._getData = this ._getDataFun(opt.mode);
// 設定預覽顯示程式
this ._show = opt.mode !== " filter " ? this ._simpleShow : this ._filterShow;
};
// 根據浏覽器擷取模式
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 = {
// 設定預設屬性
_setOptions: function (options) {
this .options = { // 預設值
mode: ImagePreview.MODE, // 預覽模式
ratio: 0 , // 自定義比例
maxWidth: 0 , // 縮略圖寬度
maxHeight: 0 , // 縮略圖高度
onCheck: function (){}, // 預覽檢測時執行
onShow: function (){}, // 預覽圖檔時執行
onErr: function (){}, // 預覽錯誤時執行
// 以下在remote模式時有效
action: undefined, // 設定action
timeout: 0 // 設定逾時(0為不設定)
};
return $$.extend( this .options, options || {});
},
// 開始預覽
preview: function () {
if ( this .file && false !== this .onCheck() ) {
this ._preview( this ._getData() );
}
},
// 根據mode傳回資料擷取程式
_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;
}
},
// 濾鏡資料擷取程式
_filterData: function () {
this .file.select();
try {
return document.selection.createRange().text;
} finally { document.selection.empty(); }
},
// domfile資料擷取程式
_domfileData: function () {
return this .file.files[ 0 ].getAsDataURL();
},
// 遠端資料擷取程式
_remoteData: function () {
this ._setUpload();
this ._upload && this ._upload.upload();
},
// 一般資料擷取程式
_simpleData: function () {
return this .file.value;
},
// 設定remote模式的上傳檔案對象
_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 " ); }
});
}
},
// 預覽程式
_preview: function (data) {
// 空值或相同的值不執行顯示
if ( !! data && data !== this ._data ) {
this ._data = data; this ._show();
}
},
// 設定一般預載圖檔對象
_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;
},
// 設定濾鏡預載圖檔對象
_filterPreload: function () {
if ( ! this ._preload ) {
var preload = this ._preload = document.createElement( " div " );
// 隐藏并設定濾鏡
$$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 ; }
// 設定濾鏡并顯示
this .img.style.filter = " progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod='scale',src=' " + data + " ') " ;
this ._imgShow( ImagePreview.TRANSPARENT, preload.offsetWidth, preload.offsetHeight );
},
// 顯示預覽
_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
);
// 設定預覽尺寸
style.width = Math.round( width * ratio ) + " px " ;
style.height = Math.round( height * ratio ) + " px " ;
// 設定src
img.src = src;
this .onShow();
},
// 銷毀程式
dispose: function () {
// 銷毀上傳檔案對象
if ( this ._upload ) {
this ._upload.dispose(); this ._upload = null ;
}
// 銷毀預載圖檔對象
if ( this ._preload ) {
var preload = this ._preload, parent = preload.parentNode;
this ._preload = preload.onload = preload.onerror = null ;
parent && parent.removeChild(preload);
}
// 銷毀相關對象
this .file = this .img = null ;
},
// 出錯
_error: function (err) {
this .onErr(err);
}
}
完整執行個體下載下傳(asp.net版)
完整執行個體下載下傳(asp版)
由felsenlee提供的jsp版:完整執行個體下載下傳(jsp版)