Flash AS3 相对于AS2 新的特性和改动

本文介绍了ActionScript 3 相对于 ActionScript 2 有哪些新的特性和改动。并在文章的最后一步步的教大家如何利用 Flex Builder 来编译并运行第一个 AS3 程序。语法方面的增强和改动:

  • 引入了 package(包) 和 namespace(命名空间) 两个概念。其中 package 用来管理类定义,防止命名冲突,而 namespace 则用来控制程序属性方法的访问。
  • 新增内置类型 int (32比特整数),uint(非负32比特整数),用来提速整数运算;
  • 新增 * 类型标识,用来标识类型不确定的变量,通常在运行时变量类型无法确定时使用。在 AS2 中这种情况下需要用 Object 赖作为类型表识;
  • 新增 is 和 as 两个运算符来进行类型检查。其中 is代替 AS2 中的 instanceof 来查询类实例的继承关系,而 as 则是用来进行不抛错误的类型转换。
  • 新增 in 运算符来查询某实例的属性或其prototype中是否存在指定名称的属性。
  • 新增 for each语句来循环操作 Array 及 Object实例。
  • 新增 const 语句来声明常量。
  • 新增 Bound Method 概念。当一个对象的方法被付值给另外一个函数变量时,此函数变量指向的是一个 Bound Method,以保证对象方法的作用域仍然维持在声明此方法的对象上。这相当于 AS2 中的 mx.util.Delegate 类,在 AS3 中这个功能完全内置在语言中,不需要额外写代码。
  • AS3 的方法声明中允许为参数指定默认值(实现可选参数)。
  • AS3 中方法如果声明返回值,则必须明确返回。
  • AS2 中表示方法没有返回值的 Void 标识,在 AS3 中变更为 void。
OOP方面的增强

通过类定义而生成的实例,在 AS3 中是属于 Sealed 类型,即其属性和方法无法在运行时修改。这部分属性在 AS2 中是通过类的 prototype 对象来存储,而在 AS3 中则通过被称为 Trait 的概念对象存储管理,无法通过程序控制。这种处理方式一方面减少了通过 prototype 继承链查找属性方法所耗费的时间(所有父类的实现方法和属性都会被直接复制到对应的子类的 Trait 中),另一方面也减少了内存占用量,因为不用动态的给每一个实例创建 hashtable 来存储变量。如果仍然希望使用 AS2 中类实例在运行时的动态特性,可以将类声明为 dynamic。api方面的增强

  • 新增 Display API,使 AS3 可以控制包括 Shape, Image, TextField, Sprite, MovieClip, Video, SimpleButton, Loader在内的大部分 DisplayList 渲染单位。这其中 Sprite 类可以简单理解为没有时间轴的 MovieClip,适合用来作为组件等不需要时间轴功能的子类的基础。而新版的 MovieClip 也比 AS2 多了对于 Scene(场景)和 Label(桢标签)的程序控制。另外,渲染单位的创建和销毁通过联合 new 操作符以及 addChild/removeChild 等方法实现,类似 attachMovie 的旧方法已被舍弃,同时以后也无须去处理深度值。
  • 新增 DOM Event API,所有 在DisplayList 上的渲染单位都支持全新的三段式事件播放机制,以 Stage 为起点自上而下的播报事件到 target 对象(此过程称为 Capture Phase),然后播报事件给 target 对象(此过程称为 Target Phase),最后在自下而上的播报事件(此过程称为 Bubbling Phase)。
  • 新增内置的 Regular Expressions (正则表达式)支持,使 AS3 能够高效地创建、比较和修改字符串,以及迅速地分析大量文本和数据以搜索、移除和替换文本模式。
  • 新增 ECMAScript for XML (E4X)支持。 E4X 是 AS3 中内置的 XML 处理语法。在 AS3 中 XML 成为内置类型,而之前的 AS2 版本 XML 的处理 api 转移到 flash.xml.*包中,以保持向下兼容。
  • 新增 Socket类,允许读取和写入二进制数据,使通过 AS 来解析底层网络协议(比如 POP3, SMTP, IMAP, NNTP 等)成为可能,使 Flash Player 可以连接邮件服务器和新闻组。
  • 新增 Proxy 类来替代在 AS2 中的 Object.__resolve 功能。
  • 新增对于 Reflect (反射)的支持,相关方法在 flash.util.* 包中。
  • AS3 中使用URLRequest 和URLLoader 与服务器交互

    AS3 中使用 URLLoader 与 URLRequest 取代了先前版本 LoadVars 方法. 初学者可能又会迷糊了.
    在现在帮助系统没有完善的情况下 (Flash 9 没有帮助, Flex Builder 2 的只有英文), 这里写篇简单的教程, 方便大家往 AS3 过渡.

    在 AS3 中, 有关于网络操作的内置类全部在 flash.net 里. 下面是本教程要用到的类的清单 :

    URLLoader : 用于从网络或者本地读取文件, 可以通过设置他的 dataFormat 属性改变收到的文本类型.
    与 AS2 的 LoadVars 不同的是, 他的默认值 URLLoaderDataFormat.TEXT 即纯文本格式, 所以在读取外部文本变量的时候得修改一下他的 dataFormat 为URLLoaderDataFormat.VARIABLES. 不过在 AS2 中没有该属性, 取代的是contentType 属性.

    URLRequest : 用于传递变量到服务器, 以及 URLLoader 要 load 的目标路径. 可以通过设置他的 contentType 属性改变发送到服务器的变量类型, 默认是 application/x-form-urlencoding, 也就是 URLEncode 编码.

    URLVariables : 用于配置传递到服务器变量的键 / 值集合, 如user1=Kakera&user2=Eigo.

    URLLoaderDataFormat : 用于设置 URLLoader 读取文件的类型, 有 TEXT (纯文本), VARIABLES (URLEncoding 的键 / 值集合), BINARY (2 进制格式), URLLoader 会根据相应的类型进行解码操作, 如解码 URLEncode

    同时还有其他不常用的 :
    URLRequestMethod : 决定使用哪种方式传递数据到服务器, POST 或者 GET.
    URLReqeustHeader : 用于配置传递到服务端的 HTTP 标头.

    值得一提的是, URLLoader 还有相当完整的事件让我们来获取读取数据的状态, 下面是有关 URLLoader 事件的清单.

    complete : 使用 URLLoader.load() 方法后, 数据完全加载完毕时触发, 通常如果能够触发这个事件的话, 说明你的程序没有问题.

    httpStatus : 使用 URLLoader.load() 方法后, 获取 HTTP 状态代码时触发, 通过判断他的 state 属性我们可以获得远程文件的加载状态. 成功 (200), 没有权限 (403), 找不到文件 (404), 服务器内部错误 (500) 等等. 这个事件总是在 compelete 之前被触发.

    ioError : 使用 URLLoader.load() 方法时, 发生致命错误时触发, 我还没碰到过..

    open : 使用 URLLoader.load() 方法后, 开始从服务器下载数据时触发一次, 此时的 URLLoader.bytesLoaded 一定是 0.

    progress : 使用 URLLoader.load() 方法后, 在从服务器下载数据的过程中持续触发, 通过侦听他的变化我们可以很方便的为 URLLoader 做加载状态的显示.

    securityError : FlashPlayer 的安全错误, 比如跨域加载, 从硬盘 (文件系统) 发送 / 读取服务器上的数据

  • 另外文档关于AS3:

  • 首先 say hello 一下,在输出面板 trace 出 “Hello World!”。复习一下AS2的类代码:

    class net.eidiot.learnAS3.HelloAs2{
        public function HelloAs2(){
            trace("Hello World!");
        }
    }

    为了让这段代码工作,需要在Flash IDE里场景的第一帧输入代码:

    import net.eidiot.learnAS3.HelloAs2;
    var hello:HelloAs2 = new HelloAs2();

    再来看看AS3的类:

    package net.eidiot.learnAS3
    {
        import flash.display.Sprite;   
        public class HelloAs3 extends Sprite
        {
            public function HelloAs3(){
                trace("Hello World!");
            }
        }
    }

    打开Flash 9,在文档属性的“Document class”里输入包名和类名,如图:

     

    下面来看看区别。在AS3的类里多了一个package关键字,后面跟上类的包名(如果fla和类放在相同的文件夹就可以什么都不跟)。这样在声明类的时候就不用带上包名了。

    public class HelloAs3 extends Sprite

    class 关键字的前面多了一个 public 。在AS3里类还可以是 internal 。如果声明类为 internal 则只有同一个包里的其他类可以引用导入,包外的任何类都将访问不到它。此类继承了 Sprite 。AS3的类如果想使用 MC 的事件或方法必须让它继承 MovieClip 或者 Sprite 。Sprite 可以理解为没有时间轴的 MovieClip 。

    最后一步是把它设置为 fla 的 Document class ,这样类 HelloAs3 就和文档 helloAs3.fla 绑定在一起了。

    是不是感觉AS3太麻烦了?高射炮打蚊子,是要费劲一点的。

    尝试用AS3做一个简单的计数器。先来看看最后的效果:

    public function ShowTimer(){
        stage.scaleMode = StageScaleMode.NO_SCALE;
        stage.align = StageAlign.TOP_LEFT;
        initMc();
    }

    AS3里新加了很多的常量来代替字符串。这给我们带来了很大的方便。比如要限制影片的缩放模式为固定尺寸,AS2时的代码为

    Stage.scaleMode = "noScale";

    值是一个字符串,在输入的时候是没有代码提示的,很容易输错(我经常是到帮助文档里把字符串复制过来)。而在AS3里的代码为:

    stage.scaleMode = StageScaleMode.NO_SCALE;

    原来的字符串 “noScale” 由常量 StageScaleMode.NO_SCALE 代替。这样可以使用代码提示自动完成,有效避免了因为输错而造成的程序bug(而且很方便  )。同样的字符串常量还有一些事件类型比如 MouseEvent.CLICK 代替”click” 等等。

    private function initMc():void{
        showTxt = new TextField();
        addShow(showTxt,10,10,310,20);
        addLabel(setDelayLabel,10,40,"delay:");
        //...other code
    }

    添加文本框和按钮。注意,需要再次引用的文本框必须显式初始化,否则在其他地方引用此变量将返回 null 。

    private function addLabel(txt:TextField,x:uint,y:uint,text:String):void{
        txt = new TextField();
        txt.x = x;
        txt.y = y;
        txt.text = text;
        addChild(txt);
    }

    AS3里所有的东西都是 new 出来的。仅仅 new 出来还不行,必须使用 addChild() 把它添加到显示列表里。

    private function addBtn(mc:Sprite,...,clickHanlder:Function):void{
        mc.mouseChildren = false;
        mc.graphics.beginFill(0x000000,0.3);
        mc.graphics.drawRect(0,0,w,h);
        mc.buttonMode = true;
        mc.addEventListener(MouseEvent.CLICK,clickHanlder);
        addChild(mc);
        //
        txt = new TextField();
        txt.name = "btnText";
        mc.addChild(txt);
    }

    在AS3里想要 mc 成为一个按钮必须设置:

    mc.buttonMode = true;

    这时看到鼠标经过mc时并没有变成手形,原因在最后一行,把 txt 添加到了 mc 里用来显示按钮文字,以致鼠标事件的目标对象为txt而不是期望的mc。为了解决这个问题需要加上一句:

    mc.mouseChildren = false;

    以保证mc为鼠标事件的目标对象(target objects)。

    AS3里所有的可见对象都是DisplayObject的子类,而DisplayObject是EventDispatcher的子类

    Sprite → DisplayObjectContainer → InteractiveObject → DisplayObject → EventDispatcher → Object

    也就是说所有的可见对象都可以直接addEventListener。

    mc.addEventListener(MouseEvent.CLICK,clickHanlder);

    这里用常量 MouseEvent.CLICK 代替了事件类型 “click” 。此类常量以后不再赘述。

    mc.graphics.beginFill(0x000000,0.3);
    mc.graphics.drawRect(0,0,w,h);

    AS3里所有的绘图方法都放在了 Graphics 里。Sprite的graphics属性就是一个Graphics。除了基本的 beginFill ,beginBitmapFill 之类,又增加了新的 drawCircle 、drawEllipse、drawRect 等方法,再也不用没完没了地 moveTo 、lineTo 了。 

    public function startTimer(event:MouseEvent):void{
        //...code here
    }

    下面是主要的内容了:Timer。

    var delay:uint = setDelayTxt.text;
    var repeatCount:uint = setRepeatCountTxt.text;
    if(timer == null){
        timer = new Timer(delay,repeatCount);
    }

    uint是AS3新加的数据类型,表示32位的正整数(int 表示32位有符号的整数)。Timer的构造函数接受两个参数,delay 是 “timer” 事件延迟的毫秒数,repeatCount 是循环的次数,默认为0,即一直循环下去直到 stop 或者 reset 。

    timer.addEventListener(TimerEvent.TIMER,timerHandler);
    timer.addEventListener(TimerEvent.TIMER_COMPLETE,timerCompleteHandler);

    timer广播两个事件,每隔 delay 指定的毫秒广播一次 “timer” 事件,循环repeatCount次之后广播 “timerComplete” 事件。

    timer.start();
    startBtn.getChildByName("btnText").text = " stop ";

    timer 在 start 之后开始执行,此时 running 属性为 true 。把 startBtn 设置为 “stop”,注意AS3是拿不到startBtn的child的,因为 Sprite 不是动态类,无法声明它的child。这时候想要拿到startBtn内的文本框就要使用 getChildByName 方法。当然要先给child一个name:

    //function addBtn
    txt.name = "btnText";

    最后是 stop 和 reset 的区别:reset 在 stop 之后把 currentCount 属性设为 0 。可以通过 最后编译的swf 体会一下。

    做东西的时候发现AS3的EventDispatcher类好像不能传参数。请教 bogey ,答曰,写一个类继承 Event ,把参数放在构造里。试了一下,果然好用。

    页面生成部分就不介绍了,唯一值得注意的是 TextField 类增加了一个 appendText 方法。以前的

    myTxt.text += "your text";

    应该写成:

    myTxt.appendText("your text");

    如果使用老的方法编译器会提示:这招太慢了,试试新的吧。(Appending text to a TextField using += is many times slower than using the TextField.appendText() method.)
      EventDispatcher 类的 dispatchEvent 方法只接受一个参数:event:Event。为了在广播事件的同时传递参数,写一个继承Event的类:TestEvent

    internal class TestEvent extends Event{
        //code here
    }

    将事件类型声明为一个字符串常量:

    public static const TRACE_INOF:String = "traceInfo";

    将要传递的参数和事件类型一起放在构造函数里

    private var _who:String;
    private var _info:String;
    public function TestEvent(type:String,who:String,info:String){
        super(type);//调用父类 Event 的构造函数
        _who = who;
        _info = info;
    }

    广播事件的代码:

    public function dispatch(who:String,info:String):void{
    dispatchEvent(new TestEvent(TestEvent.TRACE_INOF,who,info));
    }

    注册监听器:

    dispatcher.addEventListener(TestEvent.TRACE_INOF,onTraceInfo);

    接收事件和参数:

    public function onTraceInfo(event:TestEvent):void{
        var traceTxt:TextField =
                    getChildByName("traceTxt") as TextField;
        traceTxt.appendText(event.who+"dispatch:"+event.info);
    }

    这里需要注意的是 as ,新的类型转换操作符,将 getChildByName() 返回的 DisplayObject 转换为前面声明的类型 TextField 。如果转换失败将返回 null 。官方给的例子:

    public var myArray:Array = ["one", "two", "three"];
    trace(myArray as Array);  // one,two,three
    trace(myArray as Number); // null
    trace(myArray as int);    // null

    首先,AS3里function的参数可以有默认值了。

    public function TestFunc(){
        myFunc();
    }
    private function myFunc(para1:int=10,para2:String="str"):void{
        trace(para1 + " , " + para2);    //10 , str
    }

    AS3里不能给出多余的参数,

    public function TestFunc(){
        myFunc(2,"3",4);
    }
    private function myFunc(para1:int,para2:String):void{
        trace(para1 + " , " + para2);
    }

    编译器给出参数不匹配的错误:ArgumentError: Error #1063: Argument count mismatch on TestFunc/TestFunc::myFunc(). Expected 2, got 3.

    这样以前那种用 arguments 拿到不固定参数的方法就不能用了。AS3给出一个新的关键字:… (rest) parameter

    public function TestFunc(){
        myFunc(2,"3",4,"5",true);
    }
    private function myFunc(para1:int,para2:String,... more):void{
        trace(para1 + " , " + para2);    //2 , 3
        trace(more);    //4,5,true
    }

    在固定的参数后面跟一个 “…” 和一个表达式(如例子中的“more”),“…” 后面所有的参数将被放到以该表达式命名的数组中。注意 “…” 必须是最后一个参数。

    如果使用 “…” arguments 就不可用了,自然也就拿不到 arguments.callee(对当前正在执行的函数的引用),所以在确定不使用 callee 的情况下才能用 “…”。

    提到 arguments ,arguments.caller 已经被 “remove” 了。要想拿到 caller 需要把调用函数的 callee 作为参数传给被调用函数。官方的例子:

    package {
        import flash.display.Sprite;
     
        public class ArgumentsExample extends Sprite {
            private var count:int = 1;
           
            public function ArgumentsExample() {
                firstFunction(true);
            }
     
            public function firstFunction(callSecond:Boolean) {
                trace(count + ": firstFunction");
                if(callSecond) {
                    secondFunction(arguments.callee);
                }
                else {
                    trace("CALLS STOPPED");
                }
            }
     
            public function secondFunction(caller:Function) {
                trace(count + ": secondFunction/n");
                 count++;
                 caller(false);
            }       
        }
    }

    AS3有了按钮类:SimpleButton ,可以为四种状态分别指定不同的 DisplayObject 。但是 SimpleButton 没有继承 DisplayObjectContainer 类,也就是不能给它添加其他的 child 。如果要创建一个带文字的 Button 怎么办?两种方案:

    • 方案一:把文字加到每种 state 里。因为 Shape 也没有继承 DisplayObjectContainer 类,要添加文字 state 就要用 Sprite 。优点是每种状态可以有不同的文字颜色、大小、位置等。缺点是不方便改文字内容。
    • 方案二:把 SimpleButton 和 TextField 一起放到一个 Sprite 里。这样 SimpleButton 的 state 可以用 Shape 以节省内存空间。优缺点和方案一相反。 

    创建一个按钮很简单,为它的四种状态分别指定一个 DisplayObject 就可以了:

    btn = new SimpleButton();
    btn.name = "btn";
    btn.downState = new BtnStatusShape2(downColor,w,h);
    btn.overState = new BtnStatusShape2(overColor,w,h);
    btn.upState = new BtnStatusShape2(upColor,w,h);
    btn.hitTestState = btn.upState;
    addChild(btn);

    注意必须指定 hitTestState ,就是Flash IDE里创建 Button 时的 hit 帧,响应鼠标事件的区域,如果没有它按钮就失去作用了。一般设置它和 upState 一样就可以了。

    第二种方案的每种 state 都是一个 Shape(→ DisplayObject → EventDispatcher → Object):

    internal class BtnStatusShape2 extends Shape{
    public function BtnStatusShape2(bgColor:uint,w:uint,h:uint) {
        graphics.lineStyle(1,0x000000,0.8)
        graphics.beginFill(bgColor,0.8);
        graphics.drawRoundRect(0,0,w,h,8);
        graphics.endFill();
    }
    }

    方案一没有什么好说的。方案二如果想让 btn 响应鼠标事件可以重写装载它的 Sprite 的 addEventListener 方法:

    public override function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void{
        btn.addEventListener(type,listener);
    }

    要重写继承自父类的方法必须使用 override 关键字。而且重写的方法必须有父类方法完全相同的参数名称、数量和类型。

    当然方案二也可以通过监听 MOUSE_OVER、MOUSE_OUT、CLICK 等 MouseEvent 来改变不同状态的文本显示。其他内容参考类代码

    AS3支持 label 了,跳出多层循环可以这样写:

    outerLoop: for (var i:int = 0; i < 10; i++) {
        for (var j:int = 0; j < 10; j++) {
            if ( (i == 8) && (j == 0)) break outerLoop;
            trace(10 * i + j);
        }
    }

    AS2 的时候只能多加个变量判断:

    var needBreak:Boolean = false;
    for (var i:Number = 0; i < 10; i++) {
        for (var j:Number = 0; j < 10; j++) {
            if ( (i == 8) && (j == 0)) {
                needBreak = true;
                break;
            }
            if(needBreak) break;
            trace(10 * i + j);
        }
    }

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值