阿当的博客











{四月 30, 2008}   a标签伪协议触发事件和onclick触发事件的this指针问题
   今天在做一个点击事件的时候,用的是a标签的href="javascript:XXX(this)"来触发,发现怎么样都出错,很奇怪this居然没有parentNode,后来试了一下,在XXX()中的第一句写上alert(obj==window),发现居然弹出true,也就是说,用href="javascript:XXX(this)"来调用XXX()的时候,this指针并不是指向当前DOM对象的,而是指向window。用onclick="XXX(this)",再试试,发现这次就传对了。


{四月 26, 2008}   [原创 js] js访问样式表函数

因为写js经常需要用到访问样式,我们常用的做法是通过 DOM.style.XXX来读写样式信息的。可是DOM.style这种写法只能访问<DOM style=""></DOM>,这样在标签里内置的样式,如果样式写在<style type="text/css"></style>,或者.css文件里,那么就办法读到样式了。

其实呢,还有别的方法可以读到这些样式信息,方法有两种,一种是通过document.styleSheets对象,另一种是通过“最终样式”对象。其中IE中这个对象叫做currentStyle,FF中这个对象叫做document.defaultView。我将这两个类打包了一下,做了一个用于访问样式信息的函数,如下:

//===========================访问样式表函数====================================
function returnStyle(obj,styleName){
var myObj = typeof obj == "string" ? document.getElementById(obj) : obj;
if(document.all){
   return eval("myObj.currentStyle." + styleName);
} else {
   return eval("document.defaultView.getComputedStyle(myObj,null)." + styleName);
}
}

函数有两个参数:

obj:              访问的对象,类型为DOM对象,或者是对象的id;

styleName:    需要访问的样式名称。类型为string,但是名称不能用"-"号,要用像style.对象的属性名一样的大小写混写名称,例如background-color要写成backgroundColor。

函数返回值为 string类型。

注意:这个方法只能访问样式文件,不能写。如果要写样式,还是要用DOM.style.XXX的方法。另外,FF下有些样式访问有问题,例如padding,margin。如果样式中设置了padding,margin等值,我们可以用marginLeft来返回值。

========================= 以下是demo ===========================

<!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" />
<style type="text/css">
#demo{background-color:#000;padding:10px;color:#fff;width:200px;}
</style>
<script type="text/javascript">
//===========================访问样式表====================================
function returnStyle(obj,styleName){
var myObj = typeof obj == "string" ? document.getElementById(obj) : obj;
if(document.all){
   return eval("myObj.currentStyle." + styleName);
} else {
   return eval("document.defaultView.getComputedStyle(myObj,null)." + styleName);
}
}

</script>
<title>阿当制作</title>
</head>

<body>
<div id="demo">这里是测试内容</div>
<br /><br />
<a href="###" onclick="alert(returnStyle(‘demo’,'width’));">点击测试</a>
</body>
</html>



{四月 25, 2008}   [原创 js] 点击展开关闭效果

    因为工作中老是需要这个功能,本来也不是很麻烦,就把它写成一个可重用的函数好了。代码很简单。

//===========================点击展开关闭效果====================================

function openShutManager(oSourceObj,oTargetObj,shutAble,oOpenTip,oShutTip){
var sourceObj = typeof oSourceObj == "string" ? document.getElementById(oSourceObj) : oSourceObj;
var targetObj = typeof oTargetObj == "string" ? document.getElementById(oTargetObj) : oTargetObj;
var openTip = oOpenTip || "";
var shutTip = oShutTip || "";
if(targetObj.style.display!="none"){
   if(shutAble) return;
   targetObj.style.display="none";
   if(openTip && shutTip){
    sourceObj.innerHTML = shutTip;
   }
} else {
   targetObj.style.display="block";
   if(openTip && shutTip){
    sourceObj.innerHTML = openTip;
   }
}
}

函数一共有5个参数,作用如下:

oSourceObj:点击事件的对象,类型为DOM对象,或者对象的id;

oTargetObj:展开关闭的对象,类型为DOM对象,或者对象的id;

shutAble:对象是否可关闭,类型为布尔值,可选,默认为false;

oOpenTip:对象关闭时,点击源的文字,类型为String,可选;

oShutTip:对象打开时,点击源的文字,类型为String,可选.

================================= 下面放demo ==================================

<!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" />
<style type="text/css">
#box,#box2,#box3,#box4{padding:10px;border:1px solid green;}
</style>
<script type="text/javascript">
//===========================点击展开关闭效果====================================

function openShutManager(oSourceObj,oTargetObj,shutAble,oOpenTip,oShutTip){
var sourceObj = typeof oSourceObj == "string" ? document.getElementById(oSourceObj) : oSourceObj;
var targetObj = typeof oTargetObj == "string" ? document.getElementById(oTargetObj) : oTargetObj;
var openTip = oOpenTip || "";
var shutTip = oShutTip || "";
if(targetObj.style.display!="none"){
   if(shutAble) return;
   targetObj.style.display="none";
   if(openTip && shutTip){
    sourceObj.innerHTML = shutTip;
   }
} else {
   targetObj.style.display="block";
   if(openTip && shutTip){
    sourceObj.innerHTML = openTip;
   }
}
}
</script>
<title>无标题文档</title>
</head>

<body>
<p><a href="###" onclick="openShutManager(this,’box’)">点击展开</a></p>
<p id="box" style="display:none">
   这里面放的是box的内容.
</p>
<p><a href="###" onclick="openShutManager(this,’box2′,true)">点击展开</a></p>
<p id="box2" style="display:none">
   这里面放的是box的内容.
</p>
<p><a href="###" onclick="openShutManager(this,’box3′,false,’点击关闭’,'点击展开’)">点击展开</a></p>
<p id="box3" style="display:none">
   这里面放的是box的内容.
</p>
<p><button onclick="openShutManager(this,’box4′,false,’点击关闭’,'点击展开’)">点击展开</button></p>
<p id="box4" style="display:none">
   这里面放的是box的内容.
</p>
</body>
</html>



{四月 22, 2008}   开始做在线拍照功能了

   今天开始要做在线拍照的功能了。参考的例子就是51的在线拍照。

    小试了一下,原理不是太难。一个是用于捕获摄像头的类,然后是用滤镜来实现特殊效果。比较复杂的一点是关于图片上传至服务器端的实现。另外,关于滤镜的矩阵我之前也没有好好研究过。这次最头疼的应该就是这两个方面了。

     至于用flash还是用flex,我选择还是用flex好了,进一步加强flex的能力。ok,先看看书,了解一下相关的类。



{四月 19, 2008}   RIA之争,我的看法

相比于后台的技术,这几年前端的技术发展实在太快了.而RIA是未来几年内web的重头戏,

 桌面软件web化是个趋势,office甚至ps这样重量级的软件都要web化,可以看到复杂软件web化技术上已经成为可能.相较于c/s结构,b/s结构的优势不言而喻,那么有什么理由不相信未来几年内,软件web化将成为大热门,从而引起整个网络的再一次繁荣?这个领域很新,把握住这个方向,就能成为这个领域的先行者.本曾想做个前后台兼通的程序员的,也想过完全抛弃技术,专心做设计的.这两方面的书没少买,也没少用过心.可是,事情的发展往往不完全由自己掌控.机缘巧合,现在已经专攻前端技术了.好在真正合格的前端少,竞争不算太激烈,而需求量又大,超受业内重视,头疼的是前端的技术真的是花样太多,而且更新太快.选择这一领域,真不知是幸还是不幸.

为什么RIA如此重要呢?其实道理很简单,对于一个普通的用户来说,对于网站的印象好坏完全取决于前台.一个用j2EE架框+甲骨文超强组合的后台系统和一个用asp+access做的后台系统,对于普通用户来说,完全感觉不到区别,或者说区别太小.他们能看到的只是前端的体验,比如说网站的UI,网站的交互体验,特效体验.前端好的网站,就很容易得到用户的认可.这也是为什么我选择前端的原因.

 说到RIA,不得不说到三个东西:ajax,flash/flex,sliverlight.总的来说,应该将他们分成两类,一类是以js为核心,以ajax为重要武器的传统前端,即html/xhtml+js+css;另一类是嵌入html中,但是实际运行在自己的虚拟机中的富媒体,典型代表就是swf.从软件巨头微软开发sliverling可以看得出,前端富媒体很有价值.

 以js/ajax为核心的RIA技术这几年发展很迅速,js库如雨后春笋般出现,Prototype,Dojo,jquery,YUI等等等等,甚至连dw也开始自己带js库了!对于js库,我只用过jquery,感觉实在是太棒了,第一个小,第二个功能实用,第三个使用方便,第四个容易上手.学过jq之后,基本上一般的js效果都不成问题,就算是有复杂的效果,也可以用上官方UI插件,或者第三方制作的丰富插件.可是,使用插件也不是个办法啊,东插一个西插一个的,可能存在冲突隐患,管理也不是很方便.那么,可以考虑一下Dojo或者是现在如日中天的ext.Dojo我也没有用过,但是ext我试过,这库实在是太华丽了,强大的功能,漂亮的UI,实在是一见倾心.只是ext的API文档实在是太烂了,目前的中文资料也非常少,自学实在是个很大的挑战.我想,js库这一块没必要全部掌握,我们只要挑自己喜欢的库,然后用精它就好.当然,选择流行的库是比较好的,因为有大量的插件学习资料,另外,团队配合也更容易找到会用同样库的人.个人推荐学习两个库:jquery和ext.jquery小,而且灵活,是开发小型项目的首先;ext就比较大了,可是它的功能强大,做大型项目有非常大的优势.

 富媒体的发展同样迅速.sliverlight我还没有用过,不好评价,不过,口碑似乎不错.说说flash/flex吧.从as2到as3的变化实在太大了!大到我一开始用as3的时候,完全动不了手,连最简单的单击按钮trace个"hello world"我都做不到了.看了些as3的资料,总算是勉强可以用了.as3提供了更多的类,更完善的语言体系,的确是解决了很多as2时代的大问题.但让我有疑问的是,as3干嘛搞得这么复杂?一个简单的功能要导一大堆的类进来,然后******还不能传参!功能强大了,可是易用性也打了非常大的折扣.虽说as2一个mc打遍天下有它的缺陷,可是非常好用,这对flash的普及一定有非常大的作用.到了as3,不得不赶走一批用户啊.也许你会说,flashplayer内置了两个引擎,提供对as2的兼容支持啊,不喜欢as3可以接着用as2嘛.话是没错,可是,知道自己用的技术已经落后了,在积极性方面不是会遭受打击吗?说完as,再来说说新贵flex.flex说新也不算新,出来也有几年了,可是真正受到大家关注,被国内同行所熟知,也应该是最近的事.相较于flash,flex最大的优势在于它丰富的组件.同样的功能用flash实现,复杂程度也许会翻上好几倍甚至好几十倍.但是flex也有自己的弱点,它的灵活性远不及flash.也就是说,如果做动画,或者是界面独特的交互,用flash是首选,如果要做功能组件,还是用flex的好.从flex的丰富功能来看,flex打从一开始就有个深思熟虑,十分完善的构思.传统html里面有的,这里几乎都找得到,css,脚本分离,流式布局绝对定位布局,类似于ajax的异步传输.强大.

 比较一下两方面的优势和预测一下未来可能出现的局面,我的观点是:以flash/flex为首的富媒体会赢.原因如下:
1)虽然ajax和js可以带来非常不错的交互效果,js库可以让复杂的功能简单地得以实现.可是,js库就是再强,其本质还是js,而js本身的能力还是很有限的,它最大的用处是用来控制DOM和CSS,从而取得不错的UE感受,可是对于DOM,CSS之外的东西,它就无能为力了.swf不同,它支持的东西很多,包括流媒体,套接字,访问本地信息,监听网络流.js本身的功能太简单了,w3c就像是这个产品的厂商,js库就像是第三方厂商生产的产品周边一样,各厂商有自己的想法.但是想法再多,也只能做周边,改不了产品.
2)js升级,扩展难.从css的普及升级可见一斑.js,css,html这类东西并非是某个厂家的专利产品,它是一个公用的东西,任何浏览器厂商都可以开发浏览器去支持它.如果html,js,css发布了新版本,并不是说,马上就能够得到各浏览器厂商的支持.也就是说,真正让js,css,html能够得到升级的,取决于技术和商家两部分.而商家又不是一家两家,一个公用的东西,你浏览器用你的引擎解释,我浏览器用我的引擎解释,可能大家对同一事物的解释是不一样的.这就涉及到一个兼容的问题,于是有了w3c组织.w3c组织又不是浏览器厂商他老子,他凭什么要求各浏览器要按它要求来更新对html,js,css版本升能的支持?于是,我们看到css2从98年出来,过了好多年才终于熬到了出头日,而事实上css3也一早出来了,只是到现在还没被广泛支持,js就更是升级缓慢了,甚至都没有多少人知道js版本问题,以及新旧版本的区别.事实上,之前我都不知道js升过级.这么一来,带来的是什么影响呢?就是技术得不到升级,就算新技术出现了,普及起来也是个时间活.相比之下,swf文件就完全不同了.它是商业公司的专利产品,不管浏览器是什么,它们都不直接由浏览器来解释,而是运行在自己的虚拟机上.这样一来,兼容就完全不是问题了,这一点和java倒是很相似.也正是因为兼容不是问题,所以技术更新不会因为普及的问题而遭遇瓶颈.as其实是比js发展得晚的语言,可是,到as2的时候,as就已经有赶超js的势头了,可是这个时候它们仍然十分相似.看看as3吧,哈哈,已经完全脱胎换骨了,已经和js完全不在一个档次了.想想看,js有可能会像as2到as3一样,进行重大改变,从而得到质的飞跃吗?哈哈,完全不可能的事吧.再过十年,js也还是很可能只是现在这个样子,而as已经经历数次变动,变成as5,as6,甚至as7,as8了.

 技术的升级,能带来的功能增加是显而易见的.我有理由相信,未来的RIA中,哪怕是用html+js+css来制作的前端,也会靠调用as接口来实现功能.而用纯swf做前端的网站会越来越多,最终会赶超html+js+css的形式,成为前端表现的新主流.当然,html+js+css因为已经被广泛接受,另外还有Ext这样强大的js库可以抗衡一下,所以,这需要时间.只是,在华丽表面的背后,我们要看清本质,Ext就是表面再华丽,也只是js,它有着自己的瓶颈,无法超越的瓶颈.

 未来几年内,前端一定将三分天下:其一,是以Ext为代表js库将传统页面的表现形式发挥到极至;其二,Adobe的flash/flex凭着成熟的技术和丰富的经验,以及不断创新的热情,引领着前端的技术走向;其三,微软的sliverlight凭借着公司强大的技术团队和.net体系协同做战的优势,奋起直追,很有可能追赶上flash/flex.



{四月 18, 2008}   IE6中嵌入flash的奇怪问题
IE6中,如果把flash放到form标签里,会出现 flash.id未定义的报错。太奇怪了。解决办法很简单,只需要把flash放到form标签外面即可。


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



{四月 18, 2008}   [原创 js] 点击即可修改内容函数

    今天写第一篇,就放一个原创的js函数吧。

    点击即可修改内容,这个功能大家一定都见过吧?下面是我写的一个函数,功能比较全吧。

<!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>
<script type="text/javascript">
function changeContent(obj,strNum,oEvent,oWidth,oneLine,blurSave){
   if(obj.getElementsByTagName("input").length>0) return;
   function isChinese(s){
    var p = /^[\u0391-\uFFE5]+$/;
    return p.test(s);
   }
   var textOld=obj.innerHTML;
   if(!blurSave){
    if(oneLine){
     obj.innerHTML="<input type=’text’ style=’width:220px;’ value=’"+obj.innerHTML.replace( /^\s*/, "").replace( /\s*$/, "")+"’ /><input type=’button’ value=’保存’ class=’sendBtn2′ style=’padding:0px;’ /><input type=’button’ value=’取消’ class=’sendBtn2′ style=’padding:0px;’ />";
     var save=obj.getElementsByTagName("input")[1];
     var cancel=obj.getElementsByTagName("input")[2];
    } else {
     obj.innerHTML="<textarea style=’width:250px;height:50px;’>"+obj.innerHTML.replace( /^\s*/, "").replace( /\s*$/, "")+" </textarea><br /><input type=’button’ value=’保存’ class=’sendBtn2′ style=’padding:0px;’ /><input type=’button’ value=’取消’ class=’sendBtn2′ style=’padding:0px;’ />";
     var save=obj.getElementsByTagName("input")[0];
     var cancel=obj.getElementsByTagName("input")[1];
    }
   }else{
    if(oneLine){
     obj.innerHTML="<input type=’text’ style=’width:220px;’ value=’"+obj.innerHTML.replace( /^\s*/, "").replace( /\s*$/, "")+"’ />";
    } else {
     obj.innerHTML="<textarea style=’width:250px;height:50px;’>"+obj.innerHTML.replace( /^\s*/, "").replace( /\s*$/, "")+" </textarea>";
    }
   }
   var text;
   if(oneLine){
    text=obj.getElementsByTagName("input")[0];
   } else {
    text=obj.getElementsByTagName("textarea")[0];
   }
   if(typeof oWidth == "number"){
    text.style.width=oWidth+"px";
   }
   text.select();
   text.onclick=function(oevent){
    if(document.all) window.event.cancelBubble=true;
    else oevent.stopPropagation();
   }
   if(!blurSave){
    save.onclick=function(oevent){
     if(text.value.replace( /^\s*/, "").replace( /\s*$/, "")==""){
      obj.innerHTML=textOld;
     }else{
      obj.innerHTML=text.value;
      obj.innerHTML=obj.innerHTML.replace(/</ig,"&lt;");
      obj.innerHTML=obj.innerHTML.replace(/>/ig,"&gt;");
      if(strNum){
       for(var i=0;i<strNum;i++){
        if(isChinese(obj.innerHTML.charAt(i))) strNum–;
       }
       obj.innerHTML=obj.innerHTML.substring(0,strNum);
      }
      if(typeof oEvent == "string"){
       try {eval(oEvent);}
       catch (e) {}
      }
      if(typeof oEvent == "function"){
       oEvent();
      }
      if(document.all) window.event.cancelBubble=true;
      else oevent.stopPropagation();
     }
     obj.style.background="transparent";
    }
    cancel.onclick=function(oevent){
     obj.innerHTML=textOld;
     obj.style.background="transparent";
     if(document.all) window.event.cancelBubble=true;
     else oevent.stopPropagation();
    }
   }else{
    text.onblur=function(){
     if(text.value.replace( /^\s*/, "").replace( /\s*$/, "")==""){
      obj.innerHTML=textOld;
     }else{
      obj.innerHTML=text.value;
      obj.innerHTML=obj.innerHTML.replace(/</ig,"&lt;");
      obj.innerHTML=obj.innerHTML.replace(/>/ig,"&gt;");
      if(strNum){
       for(var i=0;i<strNum;i++){
        if(isChinese(obj.innerHTML.charAt(i))) strNum–;
       }
       obj.innerHTML=obj.innerHTML.substring(0,strNum);
      }
      if(typeof oEvent == "string"){
       try {eval(oEvent);}
       catch (e) {}
      }
      if(typeof oEvent == "function"){
       oEvent();
      }
     }
     obj.style.background="transparent";
    }
   }
}
</script>
</head>
<body>
<p onclick="var obj=this; changeContent(this,20,’alert(obj.innerHTML)’,”,true,true)">

我是阿当 ^0^
</p>

<p onclick="var obj=this; changeContent(this,20,’alert(obj.innerHTML)’,”,false,true)">

我是阿当 ^0^
</p>

<p onclick="var obj=this; changeContent(this,20,’alert(obj.innerHTML)’,”,false,false)">

我是阿当 ^0^
</p>

<p onclick="var obj=this; changeContent(this,20,’alert(obj.innerHTML)’,”,true,false)">

我是阿当 ^0^
</p>

<p onclick="var obj=this; changeContent(this,60,’alert(obj.innerHTML)’,”,true,false)">
我是阿当 ^0^
</p>
</body>
</html>

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

函数有五个参数:
obj           要执行修改的DOM对象,
strNum     修改后,允许保留的最大值字符数,中文算两个字符,类型为数字,
oEvent     执行修改后的回调函数,可以写成字符串形式,或者function(){}形式,例如"alert(‘我是阿当’);",或者function(){alert("我是阿当");}
oWidth     输入框的长度,类型为数字。如果不设置,则使用默认值,
oneLine 输入框是否单行,类型为布尔值,为true表示单行,false表示多行。如果不设置,默认为多行显示,
blurSave 设置保存形式,类型为布尔值,如果为true表示输入框失去焦点即可保存,为false表示点击保存按钮保存内容。

因为一般情况下,点击即可修改内容是通过ajax方式提交的,那么我们需要得到修改后的内容,在oEvent参数中发送到服务器端。那么我们如何得到修改后的值呢?
<p onclick="var obj=this; changeContent(this,20,’alert(obj.innerHTML)’,”,true,true)">
我是阿当 ^0^
</p>
我们只要在调用changeContent()前,写下var obj=this,就可以在oEvent位置通过obj.innerHTML得到修改后的值。我们可以在这里写下<p onclick="var obj=this; changeContent(this,20,’sendAjax(obj.innerHTML)’,”,true,true)">).

如果要将行为分离出来也非常容易,只要写成下面的形式:
var obj=document.getElementById("XXX");
changeContent(obj,20,’alert(obj.innerHTML)’,”,true,true);




about

打造高品质的前端代码

pages
categories
archive
et cetera