zoukankan      html  css  js  c++  java
  • [原创 flex] flex制作的多文件上传组件

    效果演示地址: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",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",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{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出现在可视范围外的时候才会调用,这个也是没想到的,不过并不影响我们的功能。

  • 相关阅读:
    ASP.NET MVC案例——————拦截器
    Windows Azure Virtual Network (10) 使用Azure Access Control List(ACL)设置客户端访问权限
    Windows Azure Storage (20) 使用Azure File实现共享文件夹
    Windows Azure HandBook (5) Azure混合云解决方案
    Windows Azure Service Bus (6) 中继(Relay On) 使用VS2013开发Service Bus Relay On
    Azure PowerShell (9) 使用PowerShell导出订阅下所有的Azure VM的Public IP和Private IP
    Windows Azure Service Bus (5) 主题(Topic) 使用VS2013开发Service Bus Topic
    Azure China (9) 在Azure China配置CDN服务
    Windows Azure Storage (19) 再谈Azure Block Blob和Page Blob
    Windows Azure HandBook (4) 分析Windows Azure如何处理Session
  • 原文地址:https://www.cnblogs.com/cly84920/p/4427220.html
Copyright © 2011-2022 走看看