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

  • 相关阅读:
    Web应用网络模型
    Http协议
    Array数组标准库
    Array数组基础
    javascript--Object
    javascript--Function
    letCode-3
    面试前的准备
    面试常见问题
    面试经验总结
  • 原文地址:https://www.cnblogs.com/cly84920/p/4427221.html
Copyright © 2011-2022 走看看