JavaScript 图片上传预览效果

图片上传预览是一种在图片上传之前对图片进行本地预览的技术。
使用户选择图片后能立即查看图片,而不需上传服务器,提高用户体验。
但随着浏览器安全性的提高,要实现图片上传预览也越来越困难。
不过群众的智慧是无限的,网上已经有很多变通或先进的方法来实现。
例如ie7/ie8的滤镜预览法,firefox 3的getAsDataURL方法。
但在opera、safari和chrome还是没有办法实现本地预览,只能通过后台来支持预览。
在研究了各种预览方法后,作为总结,写了这个程序,跟大家一起分享。
上次写的简便无刷新文件上传系统最初的目的就是用来实现这个图片预览效果的。
兼容: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方法设置一般预载图片对象:

代码
if ( !this._preload ) {
    
var preload = this._preload = new Image(), oThis = this,
        onload 
= function(){ oThis._imgShow( oThis._data, this.width, this.height ); };
    
this._onload = function(){ this.onload = null; onload.call(this); }
    preload.onload 
= $$B.ie ? this._onload : onload;
    preload.onerror 
= function(){ oThis._error(); };
else if ( $$B.ie ) {
    
this._preload.onload = this._onload;
}


预载图片对象保存在_preload属性中,主要用来判断图像能否加载成功并获取图片原始尺寸。
要实现这些功能使用Image对象就足够了。
在onload中执行_imgShow显示预览,在onerror中进行出错处理。
ps:ff、chrome和safari的图片对象还有naturalHeight和naturalWidth属性可以获取图片的原始尺寸,即使图片尺寸已经修改过。

这里要注意ie6/7的gif图片载入bug,测试以下代码:

代码
<!DOCTYPE html><body><img id="img" /><div id="div"></div></body>
<script>
img.onload 
= function(){ div.innerHTML += this.complete + ""; };
img.src 
= "http://tuan.pcpop.com/image/my/loading.gif";
</script>


一般图片执行一次onload后并不会重复执行,但ie6/7的gif每次循环播放都会执行一次onload。
ps:ie8在非标准(怪辟)模式下也有相同的问题。
可以在onload的时候,判断complete是否为false来判断是否重复加载。
ps:除了ie,其他浏览器在onload时complete就已经为true了。
问题是选择另一个图片时这个complete仍然是true,这样就没有意义了。
所以只好在onload里面重置onload为null,并在每次选择文件重设onload了。

然后设置_preload的src预载图片,如果成功预载就会执行_imgShow显示预览。
要注意src的设置要在onload/onerror的设置之后,否则设置之前就加载完成的话就触发不了事件了。

_imgShow需要三个参数,包括要预览图片的src值,图片原始宽度和图片原始高度。
在_imgShow里面首先设置预览图片的尺寸:

代码
var img = this.img, style = img.style,
    ratio 
= Math.max( 0this.ratio ) || Math.min( 1,
            Math.max( 
0this.maxWidth ) / width  || 1,
            Math.max( 
0this.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 + "\")";


注意,如果路径中有“)”,“%”这类字符的话,直接拼接到滤镜字符串中会出现类似sql注入的问题。
程序会先对这些敏感字符进行escape编码:

data = this._data.replace(/[)'"%]/g, function(s){ return escape(escape(s)); });


为什么要做两次escape编码呢?测试时发现“%”只转一次的话,遇到“%40”之类的字符时还是会出问题。
所以我推测,字符在使用前会进行两次unescape解码,于是对应的做两次escape编码果然没问题了。
虽然预载对象是直接设置滤镜的src属性,但也有“%”的拼接字问题,所以也要escape编码。
ps:虽然单引号和双引号这里并不是必要,还是一起替换掉安心点。

还要注意预览对象不要用filters.item的方式设置滤镜。
因为元素插入文档之前,并不能通过filters.item获取滤镜对象,但能通过style预先设置filter。
所以在不确定元素位置的情况下,只能用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的FilensIDOMFile


【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,
            onload 
= function(){ oThis._imgShow( oThis._data, this.width, this.height ); };
        
this._onload = function(){ this.onload = null; onload.call(this); }
        preload.onload 
= $$B.ie ? this._onload : onload;
        preload.onerror 
= function(){ oThis._error(); };
    } 
else if ( $$B.ie ) {
        
this._preload.onload = this._onload;
    }
  },
  
//一般显示
  _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.replace(/[)'"%]/g, function(s){ return escape(escape(s)); });
    
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( 0this.ratio ) || Math.min( 1,
                Math.max( 
0this.maxWidth ) / width  || 1,
                Math.max( 
0this.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版)

转载请注明出处:http://www.cnblogs.com/cloudgamer/

如有任何建议或疑问,欢迎留言讨论。

如果觉得文章不错的话,欢迎点一下右下角的推荐。

程序中包含的js工具库CJL.0.1.min.js,原文在这里

对广告有兴趣的也欢迎点一下^_^。

cloudgamer
关注 - 7
粉丝 - 149
72
0
(请您对文章做出评价)
« 上一篇:简便无刷新文件上传系统
» 下一篇:Lazyload 延迟加载效果
posted @ 2009-12-22 00:19 cloudgamer 阅读(32215) 评论(209) 编辑 收藏 所属分类: Javascript

评论共3页: 上一页 1 2 3 
 回复 引用   
#110楼2010-03-13 21:53 | 云天1[未注册用户]
@cloudgamer
<img src="img/1.gif" width="72" height="72" name="userimg" id="userimg" style="filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale);" /></td>
这个src是我默认的。我弄了一个png图片 ,在中间写了几行字,其他区域透明,如果另选一个图片,原来的图片中间的字会重叠在新选图片的上方

 回复 引用 查看   
#111楼[楼主]2010-03-13 22:06 | cloudgamer      
@云天1
那是这里的预览并不是用src的
而是用滤镜
你可以onchange的时候src换一个透明图片的链接就可以了

 回复 引用 查看   
#112楼[楼主]2010-03-15 10:05 | cloudgamer      
@云天1
我测试过

document.getElementById("userimg").filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src =dFile.value;
只能在本地取实际路径
放到服务器就是显示c:\fakepath\文件名
这样的地址的

 回复 引用 查看   
#113楼2010-03-17 15:47 | idche      
太强大了。呵呵。经常来学习你的东西。缺很少留言。真是不好意思啊。
 回复 引用   
#114楼2010-03-19 15:34 | shore1111[未注册用户]
博主啊,有个问题我一直不明白
AddPreview和ShowPreview是不是循环调用啊
现在我上传文件到服务器,如果把showpreview中最后调用的addpreview去掉的话,可以上传,当然只是一个文件
但是不去掉的话根本就上传不了啊,博主知道是什么原因吗?
谢谢!

 回复 引用   
#115楼2010-03-19 15:36 | shore1111[未注册用户]
对了,是第二种图片上传方式
 回复 引用   
#116楼2010-03-19 16:05 | shore1111[未注册用户]
问题解决了,file.type = "file"; file.name = "fileName";
name的名字设个动态后缀就可以了,也就是 让不同的文件的name不一样

 回复 引用 查看   
#117楼[楼主]2010-03-19 16:27 | cloudgamer      
@shore1111
不知你是用什么后台语言
解决就好

@idche
谢谢支持

 回复 引用   
#118楼2010-03-20 20:26 | chiele[未注册用户]
ie7下好像有红叉 御览的位置
不知道你们的怎么样?

 回复 引用 查看   
#119楼[楼主]2010-03-20 22:28 | cloudgamer      
@chiele
我用ietester测试好像没问题哦

谢谢楼主分享,支持!
谢谢楼主分享。 支持。

继续努力。

 回复 引用 查看   
#122楼2010-04-06 21:43 | Linertz||老李      
我的ie7也有叉,是不是透明图片的链接问题。
 回复 引用 查看   
#123楼[楼主]2010-04-06 22:52 | cloudgamer      
@路过都被使用了
谢谢支持

 回复 引用 查看   
#124楼[楼主]2010-04-06 22:53 | cloudgamer      
@Linertz||老李
我用ietester没问题哦
下载实例测试有问题吗

 回复 引用 查看   
#125楼2010-04-07 13:50 | yy2zmg      
楼主怎么我测试在ie6 ie7下图片有叉?
 回复 引用 查看   
#126楼2010-04-07 13:59 | Linertz||老李      
@cloudgamer
是的

 回复 引用 查看   
#127楼[楼主]2010-04-07 14:36 | cloudgamer      
@yy2zmg
6不是用滤镜
应该不会有x吧

 回复 引用 查看   
#128楼[楼主]2010-04-07 14:38 | cloudgamer      
@Linertz||老李
能说清楚你测试的工具版本环境吗
我这里没测出来

 回复 引用 查看   
#129楼2010-04-08 11:30 | .Net小菜菜      
楼主
我想问下 你的asp.net 那个版本 我怎么在预览后 读取到图片的信息呢?(字节流信息)

 回复 引用 查看   
#130楼[楼主]2010-04-08 11:33 | cloudgamer      
@.Net小菜菜
上传咯

 回复 引用 查看   
#131楼2010-04-08 11:45 | .Net小菜菜      
怎么上传呢?我现在可以正常预览
但是不知道怎么上传

是在action里设置么?

 回复 引用 查看   
#132楼2010-04-08 11:46 | .Net小菜菜      
貌似现在你的所有东西都是在客户端做的是么?
 回复 引用 查看   
#133楼[楼主]2010-04-08 11:51 | cloudgamer      
@.Net小菜菜
是啊
不过你可以参考
http://www.cnblogs.com/cloudgamer/archive/2009/12/01/Quick_Upload.html
这个系统来无刷新上传文件

 回复 引用   
#134楼2010-04-09 15:13 | gch[未注册用户]
问以下 预览图片 下面用了img 了 上面那个div ”preload“起到什么左右
 回复 引用 查看   
#135楼[楼主]2010-04-09 15:27 | cloudgamer      
@gch
一是判断能不能载入(选择了不是图片的文件就不能载入)
二是获取图片的原始尺寸

 回复 引用   
#136楼2010-04-09 17:38 | gch[未注册用户]
@cloudgamer
可以加我QQ吗 370688488 最近想学这方面 好多地方不明白 方便向你请教!

 回复 引用 查看   
#137楼[楼主]2010-04-09 17:42 | cloudgamer      
@gch
很少上q
有什么问题欢迎这里讨论

 回复 引用   
#138楼2010-04-09 18:17 | gch[未注册用户]
@cloudgamer
<div id="frameButton" style=" background-image:url(img/btn.jpg); width:77px; height:22px; border:solid 1px; cursor:pointer; "></div>
<img id="map" />
<asp:FileUpload ID="fu2" runat="server" Width="77px" Height="22px" style="display:none;"/>
<script type="text/javascript">
$('#frameButton').click(function(){
$('#fu2').click();

if($("#fu2").val()){
//alert($("#fu2").val());
//$("#map").attr("src",$("#fu2").val());
//alert($("#map").attr("src"));
var data=$("#fu2").val();
data=data.replace(/[)'"%]/g, function(s){ return escape(escape(s)); })
alert(data);
$("#map").css("filter","progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod='scale',src='"+data+"'");
$("#map").attr("src",ImagePreview.TRANSPARENT);
alert($("#map").attr("src"));
//progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod='scale',src=\"" + data + "\")
}
});
</script>我的浏览器是ie8的 我按照你的提到的方法 写 了这个测试
没有做判断 没有用preload这个div 只是想测试下 我选择图片能显示吗 但是不显示 你看看是什么原因

 回复 引用 查看   
#139楼[楼主]2010-04-09 21:46 | cloudgamer      
@gch
你直接用
var data=$("#fu2").val();
是取不到路径的
你可以参考
this.file.select();
try{
return document.selection.createRange().text;
} finally { document.selection.empty(); }
这个自己修改一下

 回复 引用   
#140楼2010-04-12 09:19 | gch [未注册用户]
@cloudgamer
预览可以了 我还是有点不明白,$("#map").attr("src",ImagePreview.TRANSPARENT);我加上这个 和不加 预览效果不一样,不加的话 预览 左上角 有个 没有图片的 时候的 默认显示图片

 回复 引用   
#141楼2010-04-12 09:20 | gch [未注册用户]
<img id="map" width="200px" height="200px" /><br />
<input id="fu2" type="file" />
整个页面就这 2个控件 那个图片怎么 怎么会有呢 望解释! 万分感谢!

 回复 引用 查看   
#142楼[楼主]2010-04-12 09:26 | cloudgamer      
@gch
他的作用正是去掉那个默认图标啊

 回复 引用 查看   
#143楼[楼主]2010-04-12 09:27 | cloudgamer      
@gch
那个图片??
哪个?

 回复 引用   
#144楼2010-04-12 10:36 | gch[未注册用户]
@cloudgamer
就是img 里不设置src的时候 页面 会有个默认的 一个 如果不用 ImagePreview.TRANSPARENT 设置成src 的话 这个默认的 也会跟着预览的图片一起出现
可惜不能贴上图 让你看下

 回复 引用 查看   
#145楼[楼主]2010-04-12 10:49 | cloudgamer      
@gch
我知道
我这个ImagePreview.TRANSPARENT 就是用来防止出现这个小图片的

 回复 引用   
#146楼2010-04-13 07:55 | BenC[未注册用户]
很不错.
不过我已经用了jQuery,如果不用CJL.0.1.min.js的话, 选择器要怎么写呢?

 回复 引用 查看   
#147楼[楼主]2010-04-13 08:21 | cloudgamer      
 回复 引用   
#148楼2010-04-13 08:35 | BenC[未注册用户]
另, 后台能不能写一个PHP版本的呀? 谢谢了
 回复 引用 查看   
#149楼[楼主]2010-04-13 09:42 | cloudgamer      
@BenC
我不懂php呢
你写好发一个给我好了:)

 回复 引用   
#150楼2010-04-13 19:28 | BenC[未注册用户]
引用cloudgamer:
@BenC
CJL里面就一个根据id获取元素的
详细看http://www.cnblogs.com/cloudgamer/archive/2009/10/29/Cloudgamer_JavaScript_Library.html

@cloudgamer
那有JQ的写法不?
我试了一下直接把 $$('id') 换成 JQ的 $('#id'), 没效果.
貌似源码里边还有很多地方也要改......

 回复 引用 查看   
#151楼[楼主]2010-04-13 21:21 | cloudgamer      
@BenC
那当然不能直接转换啦
jq得到的是jq对象你需要把方法也转换成jq能调用的方法

 回复 引用   
#152楼2010-04-14 14:30 | vivian.hsue[未注册用户]
你好,我用了asp.net版的,請問預覽後,若在client端要上傳,要如何取得idPicList的檔名,並利用QuickUpload上傳?
我在伺服器端用Request.Form("pic")取得所有檔名,但不知如何上傳到server

 回复 引用 查看   
#153楼[楼主]2010-04-14 14:59 | cloudgamer      
@vivian.hsue
你参考ImagePreview.ashx看怎么获取数据的

 回复 引用   
#154楼2010-04-28 08:57 | 碎片[未注册用户]
你好,博主,文章写的很好,受教了,支持一下

但我有个疑问:ImagePreview 方法中有一个调用,onErr: function(){},//预览错误时执行。比如我新建一个文本文档,把后缀名改成 jpg ,然后选择预览,肯定出错,执行了调用。但为什么都只在第一次错误时调用,后面就不调用了,没有明白。

 回复 引用 查看   
#155楼[楼主]2010-04-28 09:35 | cloudgamer      
@碎片
你是连续选择了同一个文件吧
程序中相同的文件只做第一次的检查

 回复 引用   
#156楼2010-04-28 09:49 | 碎片[未注册用户]
@cloudgamer
哦,能不能每当有这样的错误发生就立即调用呢?请帮我指点下,谢谢!

 回复 引用 查看   
#157楼[楼主]2010-04-28 13:40 | cloudgamer      
@碎片
这里修改一下
if ( !!data && data !== this._data ) {
this._data = data; this._show();
}
不要第二个判断就行了

 回复 引用   
#158楼2010-05-04 10:18 | 小秦as[未注册用户]
ImagePreview.ashx有什么用?
 回复 引用 查看   
#159楼[楼主]2010-05-04 10:39 | cloudgamer      
@小秦as
remote模式时从后台读数据用的

 回复 引用   
#160楼2010-05-18 20:03 | naiyi[未注册用户]
chrome下面preload执行onerror而不能执行onload,是为什么?已经从后台返回了数据,用的是jsp版本的servlet。
 回复 引用   
#161楼2010-05-18 20:21 | naiyi[未注册用户]
找到原因了,因为servlet返回的img信息里面包含了<pre></pre>标记
 回复 引用 查看   
#162楼[楼主]2010-05-18 21:47 | cloudgamer      
@naiyi
哦 呵呵

 回复 引用   
#163楼2010-05-18 22:22 | naiyi[未注册用户]
不对,我把所有浏览器都设定成remoteData模式,从servlet返回的img信息没有问题,是iframe.contentWindow.document.body.innerHTML返回的内容在img字符串外面增加个一个<pre>标签,ff3.5和chrome都有这个标签,直接就导致了img的图片无法显示,ie6不会增加这个<pre>标签,是bug吗??
 回复 引用 查看   
#164楼[楼主]2010-05-19 08:38 | cloudgamer      
@naiyi
我用ff和chrome测试过.net版
貌似可以用啊
jsp我就不懂了

 回复 引用   
#165楼2010-05-19 10:47 | naiyi[未注册用户]
和jsp应该没有关系吧。。jsp返回的是data:image/jpeg;base64打头的字符串,我用firefug看了http response的内容 也是data:image/jpeg;base64开头的 然后我把ifame设置成可见,然后用firebug的元素侦测器看iframe里面的内容就是<html><body><pre>data:image/jpeg;base64......了,你在试一下?我用的是火狐中国版3.5.9和chrome 6.0。 我现在的处理方法是把innerHTML.substring()去掉前后的<pre>标签就好了。
 回复 引用 查看   
#166楼[楼主]2010-05-19 11:22 | cloudgamer      
@naiyi
我用ff3.6.2确实没问题
没有你说的pre

 回复 引用   
#167楼2010-05-19 13:20 | naiyi[未注册用户]
好用了,是我的servlet的response.contentType没有设置正确,设置成'text/html'就可以了,谢谢你
 回复 引用 查看   
#168楼[楼主]2010-05-19 13:39 | cloudgamer      
@naiyi

原来这样

 回复 引用   
#169楼2010-05-20 10:28 | naiyi[未注册用户]
ie7中的mhtml格式的图片数据不可靠啊???
我下载了你提供的asp版本和jsp版本,用ie7运行,asp版本的显示图片没有红叉,jsp的在预览图片的上面有一个红叉,用ie7打开你在这个blog里面提供的demo也没有红叉。
然后我把ImagePreview.js和ImagePreviewd.js都放到jsp那个版本的demo里面,用ie7打开,script引用ImagePreview.js的时候不出红叉,引用magePreviewd.js的时候出出来红叉了。
为了找原因,我把两个版本中的ImagePreview.js和ImagePreviewd.js一行一行的对照了一遍,没有区别,又都转了一遍utf-8编码,也还是上面这个情况。
每次都清楚ie7缓存,现象照旧,用ie dom inspector打开看了下img的src,也都是一样的mhtml:http://......!blankImage。。。。实在是找不出来原因了,最后我用一张1*1的gif图片替换了你给的文档内置图片数据的方式,真是见鬼了。

 回复 引用 查看   
#170楼[楼主]2010-05-20 13:53 | cloudgamer      
@naiyi
jsp的我不懂也没有测试也测试不了
找到原因的话也帮我改一改吧

 回复 引用   
#171楼2010-05-20 21:46 | naiyi[未注册用户]
我也想找到原因啊。。。实在是找不出来。。。我就换成空白图片了,也不差这一次请求,mhtml数据格式不明白。
 回复 引用   
#172楼2010-05-21 16:18 | tiandizhijing[未注册用户]
非常好,非常的感谢,实在是太强悍了,太有征服力了。
 回复 引用 查看   
#173楼[楼主]2010-05-21 23:10 | cloudgamer      
@tiandizhijing
谢谢支持

 回复 引用   
#174楼2010-05-29 10:20 | jancy[未注册用户]
自己不怎么会JS,
看到楼主做出的效果,震憾啊

 回复 引用 查看   
#175楼2010-06-01 15:25 | Firmness      
很好很强大,实用!谢谢楼主分享!
 回复 引用 查看   
#176楼[楼主]2010-06-01 21:41 | cloudgamer      
@Firmness
@jancy
谢谢支持

 回复 引用   
#177楼2010-06-02 15:17 | li0201[未注册用户]
你好,我想问一下为什么加上runat="server"之后图片就不显示了呢
 回复 引用 查看   
#178楼[楼主]2010-06-02 16:19 | cloudgamer      
@li0201
加在哪里

 回复 引用 查看   
#179楼2010-06-11 00:21 | 曹聪321      
不知道有没有办法保存预览图,以方便上传完成后,以后再编辑还能看见呢?我是菜鸟额...
 回复 引用 查看   
#180楼[楼主]2010-06-11 08:54 | cloudgamer      
@曹聪321
上传完成后直接连接服务器图片地址就成了
这个就是用在没有上传的时候

 回复 引用 查看   
#181楼2010-06-11 11:29 | 曹聪      
谢谢您的回复!再请教一下:
您的例子是用
var ip = new ImagePreview( $$("idFile"), $$("idImg"), {
maxWidth: 200, maxHeight: 200, action: "ImagePreview.ashx"
});
直接传一个File对象,那怎样传图片地址呢?

 回复 引用 查看   
#182楼[楼主]2010-06-11 14:24 | cloudgamer      
@曹聪
不明白你是什么意思

 回复 引用 查看   
#183楼2010-06-11 15:21 | 曹聪      
%>_<%
就是我能不能通过传图片在服务器的路径比如"../images/aaa.jpg",来获取他的预览图?

 回复 引用 查看   
#184楼[楼主]2010-06-11 19:01 | cloudgamer      
@曹聪
上传之后就不需要这个程序了
这个程序只是用来上次前预览

 回复 引用 查看   
#185楼2010-06-12 12:02 | cai555      
比较强悍的!
 回复 引用 查看   
#186楼2010-06-16 11:46 | luobotou      
引用twxstar:
引用cloudgamer:
@twxstar
你先把文件换成utf8

恩,可以了,谢谢哈

这位大哥,你怎么改的啊。。。我怎么改了还是报错呢。。FF里面不报。。IE下报。。教教我。。谢拉!

 回复 引用 查看   
#187楼2010-06-18 17:03 | 静夜品茗      
感谢楼主,受益匪浅啊,这两天在做个上传,也是在预览这里卡壳了,好好学习下。呵呵
 回复 引用 查看   
#188楼[楼主]2010-06-18 17:20 | cloudgamer      
@静夜品茗
谢谢支持

 回复 引用 查看   
#189楼[楼主]2010-06-18 17:21 | cloudgamer      
@luobotou
直接改会变乱码的
你要打开一个utf8文本
然后把代码复制进去

 回复 引用 查看   
#190楼2010-06-21 11:47 | cocopig      
IE8下,BMP格式的图片没反应
 回复 引用 查看   
#191楼[楼主]2010-06-21 14:16 | cloudgamer      
@cocopig
我试了
没有问题
或者你把你的图片email给我试试

 回复 引用 查看   
#192楼2010-06-28 11:57 | qiuqingpo      
强烈学习
 回复 引用   
#193楼2010-07-05 12:26 | lishijie[未注册用户]
请问如何在后台取得多图片上传中的值?
 回复 引用 查看   
#194楼[楼主]2010-07-05 13:56 | cloudgamer      
@qiuqingpo
谢谢支持

 回复 引用 查看   
#195楼[楼主]2010-07-05 13:57 | cloudgamer      
@lishijie
直接提交表单就可以了
跟一般的文件上传是一样的

 回复 引用 查看   
#196楼2010-07-05 15:15 | kamus      
LZ能不能说下学习JS的过程,或者推荐几本书。不胜感激!
 回复 引用   
#197楼2010-07-07 15:09 | azraelee[未注册用户]
多谢楼主啊,在下受教甚多~!!!
 回复 引用 查看   
#198楼2010-07-14 15:08 | fangjun      
上传之前能否判断文件格式,望指教,谢谢!
 回复 引用 查看   
#199楼[楼主]2010-07-16 15:30 | cloudgamer      
@kamus
没啥
就是多写多看
有兴趣就行

 回复 引用 查看   
#200楼[楼主]2010-07-16 15:31 | cloudgamer      
@fangjun
文件格式获取value取后缀名判断就行了
可以参考
http://www.cnblogs.com/cloudgamer/archive/2008/10/20/1314766.html

 回复 引用 查看   
#201楼[楼主]2010-07-16 15:32 | cloudgamer      
@azraelee
谢谢支持

 回复 引用 查看   
#202楼2010-07-19 20:46 | cocopig      
我回邮件的时候被提示没发成功,说是你的地址不正确。163发的
 回复 引用 查看   
#203楼[楼主]2010-07-19 23:35 | cloudgamer      
@cocopig
应该可以吧
或者你放上网我下载

 回复 引用 查看   
#204楼2010-08-10 02:27 | zx36165776      
我用的ASP程序
<form id="frm" method="post" action="ImagePreview.asp" enctype="multipart/form-data">
这个提交的 但是提升错误啊 请问 是不是我提交错了吖

 回复 引用 查看   
#205楼[楼主]2010-08-10 08:25 | cloudgamer      
@zx36165776
ImagePreview.asp这个文件是用来预览不是上传文件的啊

 回复 引用   
#206楼2010-08-19 10:01 | diaoyude[未注册用户]
缺少对象: 'File(...)'
/ImagePreview/ImagePreview.asp, 第 7 行
?????????

 回复 引用 查看   
#207楼[楼主]2010-08-19 10:31 | cloudgamer      
@diaoyude
第七行是什么
无组件上传程序加上了吗

 回复 引用   
#208楼2010-08-28 21:53 | aafdsa[未注册用户]
action: "ImagePreview.ashx",

这个意思就是说每点击添加图片添一张的同时就会执行这个上传操作把图片传至服务器??是这样?而不是要到最后去点一个提交按钮再一张张的传???

 回复 引用 查看   
#209楼[楼主]2010-08-28 22:37 | cloudgamer      
@aafdsa
都可以的
程序做的是上传的过程

评论共3页: 上一页 1 2 3