flex制作的多文件flash上传组件

开发技术 2154 0 2012-08-28

flex制作的多文件flash上传组件

效果演示地址:http://www.adanghome.com/upload/  

源文件下载地址:http://www.adanghome.com/flash_upload.rar

下载后导入flexbuilder,即可按需修改。

最近在研究flex,这方面资料很少。从《程序员》杂志上看到《flex第一步》出版的时候,超高兴,周末就跑去买了。只是因为工作太忙,一直没机会学。现在项目已经基本完成了,我总算有时间来研究它了。

   项目中需要增加一个flash上传的组件,实现多文件上传,同时显示上传进度。样式要像flickr或者海内一样。首先,我想到了去网上down一个。结 果找来找去也没找到好用的,而且就算找到了,改变样式等等又会是麻烦的事情。算了,还是自己做一个吧。因为是第一次使用flex,也是第一次使用as3, 所以这个组件用了一周的时间才完成。

   先放上代码吧。

这是主mxml:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="495" height="380" fontSize="12" backgroundAlpha="0" applicationComplete="initApp()">
<mx:Script>
   <![CDATA[
    import mx.events.IndexChangedEvent;
    import mx.events.CloseEvent;
    import flash.net.FileReference;
    import flash.net.FileReferenceList;
    import flash.net.FileFilter;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.net.URLRequest;
    import mx.controls.Alert;
    import mx.events.CloseEvent;
    import flash.external.ExternalInterface;   
    public var fileRef:FileReferenceList = new FileReferenceList();      
    public var uploadImg_num:int = 0;
    public var upload_size:Number = 0;
    public var upload_size_total:Number = 0;      
    private var info:Array = new Array();
   
    //===================
    // 功能设置
    //===================
      
    /* 允许一次性上传的最大图片数 ********************/
    private var upload_maxCount:int = 50;
    /* 上传提交的服务器端文件路径 ********************/
    private var severURL:String = "photos.php?op=add_photo&tag=abc&album=0&gid=0&party_id=0&attr=0";
    /* 服务器端接收用的名称 ********************/
    private var fileName:String = "file1";
   
   
    public var urlRequest:URLRequest = new URLRequest(severURL);
    //===================
    // 浏览本地文件
    //===================
    internal function browseHandler(e:Event):void{
     var imageTypes:FileFilter = new FileFilter("Images(*.jpg,*.jpeg,*.gif,*.png)","*.jpg;*.jpeg;*.gif;*.png");
     var allTypes:Array = new Array(imageTypes);    
     fileRef.browse(allTypes);    
    }
   
    //===================
    // 选中文件,关闭对话框
    //===================
    internal function selectHandler(e:Event):void{       
     var imageNum:int = fileRef.fileList.length;
     if(imageNum>upload_maxCount){
      Alert.show("一次最多只能上传"+upload_maxCount+"张图片","提示信息");
      return;
     }
     info = new Array();
     var sizeMum:Number = 0;
     delete_btn.enabled = true;
     add_btn.enabled = true;
     for(var i:Number=0;i<imageNum;i++){
      info.push({label:fileRef.fileList[i].name,data:fileRef.fileList[i].size/1000+"KB",width:0});
      sizeMum+=fileRef.fileList[i].size;     
     }   
     process_list.dataProvider = info;
     tip_txt.text="共"+imageNum+"张图片,"+(sizeMum/(1000*1000)).toString().slice(0,-4)+"MB";
    }
   
    //===================
    // 单个文件上传结束
    //===================
    internal function completeHandler():void{
     fileRef.fileList[uploadImg_num].removeEventListener(ProgressEvent.PROGRESS,onProcessHandler);
     fileRef.fileList[uploadImg_num].removeEventListener(Event.COMPLETE,onComplete);
     upload_size+=fileRef.fileList[uploadImg_num].size;
     processBar_Total.width=(upload_size/upload_size_total)*488;
     tip_txt.text="已上传" + int(upload_size*100/upload_size_total) + "% (" + (uploadImg_num+1) +"/" + fileRef.fileList.length + ")";
     uploadImg_num++;
     process_list.scrollToIndex(uploadImg_num);
     if(uploadImg_num>=fileRef.fileList.length){
     // ExternalInterface.call("uploadCompelete");
      return;
     }
     upLoadImg(uploadImg_num);
    }
    internal function onComplete(e:Event):void{
     completeHandler();
    // Alert.show(e.toString());
    }
   
    //===================
    // 监听上传进度
    //===================
    internal function onProcessHandler(e:ProgressEvent):void{     
     var proc:uint = e.bytesLoaded/e.bytesTotal*100;
     var num:Number = uploadImg_num;    
     if(process_list.indexToItemRenderer(num)!=null)
     {
      process_list.indexToItemRenderer(num).document.processBar.width = proc*0.01*245;
      info[num].width = proc*0.01*245;          
     }   
    }
   
    //===================
    // 执行上传操作
    //===================
    internal function upLoadImg(oNum:int):void{
     try
     {
      fileRef.fileList[oNum].upload(urlRequest,fileName);
      fileRef.fileList[oNum].addEventListener(DataEvent.UPLOAD_COMPLETE_DATA,onComplete);      
      fileRef.fileList[oNum].addEventListener(ProgressEvent.PROGRESS,onProcessHandler);
     }
     catch(e:Event){
      Alert.show("上传出错","提示信息");
      completeHandler();
     }    
    }
   
    //===================
    // 点击上传按钮
    //===================
    internal function uploadHandler():void{
     if(uploadImg_num!=0) return;
     if(process_list.dataProvider==null || info.length<=0){
      Alert.show("您还未选择图片!","提示信息");
      return;
     }  
     for(var i:Number=0;i<fileRef.fileList.length;i++){    
      upload_size_total+=fileRef.fileList[i].size;          
     }         
     upLoadImg(uploadImg_num);
     delete_btn.enabled = false;
     add_btn.enabled = false;
     browse_btn.enabled = false;   
    }
   
    //===================
    // 执行删除操作
    //===================
    internal function deleteHandler(e:Event):void{
     if(process_list.selectedIndices.length<=0){
      Alert.show("您还没有选择图片","提示信息");
      return;
     }
     Alert.show("您确定要删除选定图片?","提示信息",Alert.YES|Alert.NO,process_list,alertHandler,null,Alert.NO);
     function alertHandler(evt:CloseEvent):void{
      if(evt.detail==Alert.YES){
       deleteItem();
      } else {
            
      }
     }
     function deleteItem():void{
      var selectItems:Array = process_list.selectedItems;
      var selectIndex:Array = process_list.selectedIndices;
      var iCount:int = selectItems.length;
      var sizeMum:Number = 0;
      for(var i:int=0;i<iCount;i++){
       info.splice(selectIndex[i],1);
       fileRef.fileList.splice(selectIndex[i],1);
      }
      for(var j:Number=0;j<fileRef.fileList.length;j++){      
       sizeMum+=fileRef.fileList[j].size;     
      }   
      process_list.dataProvider = info;
      tip_txt.text="共"+fileRef.fileList.length+"张图片,"+(sizeMum/(1000*1000)).toString().slice(0,-4)+"MB";
          
      if(info.length<=0){
       delete_btn.enabled = false;
      }     
     }
    }
   
    //===================
    // 执行添加操作
    //===================
    internal function addHandler(e:Event):void{
     var imageTypes:FileFilter = new FileFilter("Images(*.jpg,*.jpeg,*.gif,*.png)","*.jpg;*.jpeg;*.gif;*.png");
     var allTypes:Array = new Array(imageTypes);
     var addFileRef:FileReferenceList = new FileReferenceList();
     var sameImgIndex:Array = new Array();
     var beforeAddLength:Number = fileRef.fileList.length;    
     addFileRef.browse(allTypes);
     addFileRef.addEventListener(Event.SELECT,addSelectHandler);
    
     function addSelectHandler():void{          
      if(addFileRef.fileList.length+fileRef.fileList.length>upload_maxCount){
       Alert.show("一次最多只能上传"+upload_maxCount+"张图片","提示信息");
       return;
      }     
      for(var i:int=0;i<addFileRef.fileList.length;i++){
       for(var j:int=0;j<fileRef.fileList.length;j++){
        if(fileRef.fileList[j].name==addFileRef.fileList[i].name){
         sameImgIndex.push(i);        
        }
       }
      }    
      for(var k:Number=0;k<addFileRef.fileList.length;k++){
       fileRef.fileList.push(addFileRef.fileList[k]);
       info.push({label:addFileRef.fileList[k].name,data:addFileRef.fileList[k].size/1000+"KB",width:0});
      }
      for(var m:Number=0;m<sameImgIndex.length;m++){
       fileRef.fileList.splice(beforeAddLength+sameImgIndex[m]-m,1);
       info.splice(beforeAddLength+sameImgIndex[m]-m,1);
      }     
      var imageNum:int = fileRef.fileList.length;
      var sizeMum:Number = 0;
      for(var l:Number=0;l<imageNum;l++){      
       sizeMum+=fileRef.fileList[l].size;     
      }   
      process_list.dataProvider = info;
      tip_txt.text="共"+imageNum+"张图片,"+(sizeMum/(1000*1000)).toString().slice(0,-4)+"MB";
      delete_btn.enabled = true;
     }    
    }
   
    //===================
    // 初始化函数
    //===================  
    internal function initApp():void{
     browse_btn.addEventListener(MouseEvent.CLICK,browseHandler);
     fileRef.addEventListener(Event.SELECT,selectHandler);
     delete_btn.addEventListener(MouseEvent.CLICK,deleteHandler);
     add_btn.addEventListener(MouseEvent.CLICK,addHandler);
     /* 注册供js调用的函数 ********************/
     ExternalInterface.addCallback("uploadImg",uploadHandler);  
    }
   ]]>
</mx:Script>
<mx:Canvas>
   <mx:Button label="浏览文件" id="browse_btn"/>
   <mx:Label text="按住 Ctrl 或 Shift 键可以多选" x="85" y="3"/>
   <mx:Button label="添加文件" x="330" id="add_btn" enabled="false"/>
   <mx:Button label="删除文件" x="410" id="delete_btn" enabled="false"/>
   <mx:Canvas width="490" height="25" backgroundColor="0Xf1f1f1" x="0" y="43" borderStyle="solid" borderColor="0Xbbbbbb">
    <mx:Label text="文件名" x="5" y="3"/>
    <mx:Label text="文件大小" x="215" y="3"/>
    <mx:Label text="上传进度" x="320" y="3"/>
   </mx:Canvas>
   <mx:List x="0" y="67" width="490" rowCount="10" allowMultipleSelection="true" borderStyle="solid" borderColor="0Xbbbbbb" rowHeight="25" itemRenderer="ImageItem" id="process_list"/>
   <mx:Canvas width="490" height="25" backgroundColor="0Xf1f1f1" x="0" y="318" borderStyle="solid" borderColor="0Xbbbbbb">
    <mx:Label text="" fontWeight="bold" id="tip_txt" x="5" y="3"/>   
   </mx:Canvas>
   <mx:Canvas borderStyle="solid" x="0" width="490" y="350" height="25" borderColor="0X124fc0" backgroundColor="0xffffff">
    <mx:Canvas backgroundColor="0X124fc0" backgroundAlpha="0.5" id="processBar_Total" width="0" height="23"/>
   </mx:Canvas>   
</mx:Canvas>
</mx:Application>

这个是ImageItem.mxml:

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" height="25" borderSides="bottom" borderStyle="solid">
<mx:Label width="195" text="{data.label}" x="5"/>
<mx:Label width="100" text="{data.data}" x="210"/>
<mx:Canvas width="145" borderStyle="solid" borderColor="0X124fc0" height="7" x="320" y="5">
   <mx:Canvas width="{data.width}" id="processBar" height="7" backgroundColor="0X124fc0" backgroundAlpha="0.5"/>
</mx:Canvas>
</mx:Canvas>

然后是html:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>无标题文档</title>
<style type="text/css">
*{margin:0px;padding:0px;}
#upload_flash{width:495px;height:380px;}
</style>
<script type="text/javascript">

//上传完成后的回调函数
function uploadCompelete(){
/location.href=http://www.baidu.com;
}


function submitForm(){
   thisMovie("upload").uploadImg();
}
function thisMovie(movieName) {
   if (navigator.appName.indexOf("Microsoft") != -1) {
    return window[movieName];
   } else {
    return document[movieName];
   }
}

</script>
</head>

<body>
<div id="upload_flash">
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
    id="upload" width="100%" height="100%"
    codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab">
    <param name="wmode" value="transparent">
    <param name="movie" value="upload.swf" />
    <param name="quality" value="high" />
    <param name="bgcolor" value="#869ca7" />
    <param name="allowScriptAccess" value="sameDomain" />
    <embed src="upload.swf" quality="high" bgcolor="#869ca7" wmode="transparent"
     width="100%" height="100%" name="upload" align="middle"
     play="true"
     loop="false"
     quality="high"
     allowScriptAccess="sameDomain"
     type="application/x-shockwave-flash"
     pluginspage="http://www.adobe.com/go/getflashplayer">
    </embed>
</object>
</div>
<p><input type="button" value="提交" onclick="submitForm()" /></p>
</body>
</html>

最后是服务器端,服务器端很简单拉。我就放个php的吧:

<?php
//create the directory if doesn't exists (should have write permissons)
if(!is_dir("./files")) mkdir("./files", 0755);
//move the uploaded file
move_uploaded_file($_FILES['Filedata']['tmp_name'], "./files/".$_FILES['Filedata']['name']);
echo "aaa";
?>

===========================================================================

哈哈,效果还是蛮不错的。这里要说几个细节问题。很重要的心得:

1) as3的传值问题。 as3对事件监听只能使用函数名,不能传值,这是个很郁闷的地方。在网上搜过解决方案。大概有两种思路。一种是自定义一个类,扩展event,然后使用自 己定义的类来监听事件。这个方法呢,我找了半天也没找到个具体的代码,很不好用,烦。另一种呢,是对触发事件的对象添加一个自己定义的属性,捆在对象上。 然后呢,event.target来取得这个对象,再访问这个对象的这个属性。这种方法在写js的时候,我经常用,是很好用的方法。对象就当做是个容器, 容器绑定我需要的变量,哈哈,超好用。只是,as3好像对对象扩展属性有限制,不能像js那样随心所欲地添加,需要先扩展一下类,然后才能对相应的对象添 加属性。可是,超超超奇怪的是,这样一来,所有对象的这个属性居然指向同一地址!!!天哪,难道实例化对象之后,不是每个对象的属性都应该分配一个单纯的 地址吗??太匪夷所思了。最后,这种方法也没给我帮上忙。只能利用全局的变量来实现参数传递了。可是,这哪里算传参呢?好在我这个功能不算复杂,如果复杂 一点的功能,恐怕就惨了。

2)list组件的itemRenderer的访问。 在flash里,我们如果要访问父级元素的子级元素很简单,只需要parent_mc.child_mc.child_mc就可以访问到任意层级的子元 素。可是flex里的机制不一样。比如说这个itemRenderer应该如何访问。我首先想到,list组件会不会用一个item数组来表示它里面的元 素呢?比如,如果访问第2个元素里的adang_mc,我就用list.item[1].adang_mc来访问它。结果flexbuilder里压根就 没有相应的属性提示。后来在一英文网站看到有人提了相同的问题,才知道原来是利用.indexToItemRenderer(num).document 来访问子元素的。

3)list组件itemRenderer的渲染问题。 本以为只要用循环去一个一个访问就可以访问到所有itemRenderer里面的元素了。结果发现根本不是这么回事,只有可视范围内的 itemRenderer才会被渲染,不对,更确切地说,只有可视范围内的itemRenderer才能被访问!!! 也就是说,如果你的list有二十个元素,而可视范围只有十个,当你访问第十一个的时候,它返回值为空!当前把滚动条拉下来时,那些本不可见的元素在可见 范围的话,就可以访问了,而且本可见,现在被滚进去的元素现在又不能访问了。my god!!!这样编程多麻烦啊!我猜可能当初flex在设计list组件的时候,想尽量减少内存的开销吧,可是,这也太麻烦了吧??有没有解决办法呢? 有。我想到的是,自动进行滚动,在flex中有相应的代码,那就是.scrollToIndex(index)。只是这个方法并会在index出现在可视 范围外的时候才会调用,这个也是没想到的,不过并不影响我们的功能。

上一篇:VML是什么了?

下一篇:安装SDK时遇到&quot;Done loading packages&quot;解决变法

讨论数量:0

请先登录再发表讨论。 2024-03-29

天涯网魂
3 杠 5 星
TA 的文章
TA 的随言
TA 的资源链