概要:第一章我们主要介绍了有关RIA的背景知识以及简要地描述了一些Flex Builder2的基本知识。那么这一章我们将把目光锁定到Flex的开发模式上。在我们具体的了解怎么利用Flex开发项目之前,首先要明白MXML是什么样的一种语言和ActionScript3是怎么合作开发的,以及Adobe声称的ActionScript3已经完全实现的了面向对象编程是真的吗?以上的问题都是属于Flex编程模式的问题。Flex2编程元素包括MXML语言,ActionScript3脚本语言以及Flex2 类库
。
2
.1 MXML/ActionScript 说明
MXML
从本质上说一种XML规范的标签语言,主要用来定义描述可视用户接口,如控件类DataGrid,Label,Button,Hslider等,但是也有时用来定义一些非可视的对象比如FDS数据源的封装和绑定,比如WebService连接,数据绑定Binding,还有一些效果类Effects.MXML基本上和HTML的语法很相象,都是利用标签来定义用户接口和基本组件,但是MXML有比HTML更庞大的标签库。HTML和MXML最明显的不同是MXML文件最终由FlashPlayer来编译解析和展示,而HTML是由IE来直接解析和展示。当我们学习任何一种语言是,第一个程序都是hell world。我们也不能免俗。
<?xml version="1.0"?>
<!--
注释
-->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Box>
<mx:TextInput text="Hello World!" />
</mx:Box>
</mx:Application>
首先Flex MXML文件的注释方式为
<!--
注释
-->
。一般一个
MXML
应用文件的根标签都是
<mx:Application>
,
而
xmlns:mx="http://www.adobe.com/2006/mxml"
则定义了
Flex
类库组件的名字空间,由此说开去,如果我们有自定义的类库或者是第三方类库时,这个地方名字空间的声明是必须的。
<mx:Box>
是一个容器类对象,
<mx:TextInput text="Hello World!" />
是一个控件类对象。
MXML
机制规定容器类对象内可以无限内嵌容器类对象或者控件类对象,而控件类对象不能嵌套容器类对象或别的控件类对象。同时无论容器类对象或者控件类对象都有各自所属的属性集合,方法集合,时间集合。
TextInput
中
text
就是其中的一个属性。
ActionScript3
是被用来展示
Flex2
类对象的基础方式。因为所有的
MXML
标签对象都最终会被编译成
AS
类对象字节码的。
FlashPlayer
中的
AVM(AS
虚拟机
)
内置了
as
的所有基础标准类和方法,在运行时,
AVM
执行展示这些文件字节码。外表上
AcitionScript
和
JavaScript
是很相似的。实际上,
JavaScript
是基于
ECMA-262
标准的,而
ActionScript
是基于
ECMA-262 Edition4
规范的。和
JavaScript
一样,
ActionScript
也是一种弱类型的语言。在
OO
编程模式的实现上,
ActionScript
还远远不能让人满意,开发者可以把
AS
写成
OO
的样子,但是
OO
核心思想中的封装多态和继承却徒有其表。况且也没有足够的运行时
Runtime
处理高端需求的弹性,比如
Java
中的反射机制。作者认为,
ActionScript3
在
OO
的实现上还有空间可以拓展。
但从脚本语言的观点出发,
ActionScript
中我们的确可以方便的做很多东西。比如可以写组件事件侦听逻辑,创建新的类对象,处理回调函数,定义包
package
和组件等。在
Flex2
应用程序中利用
ActionScript
脚本的方法和场合有以下几种。
1.
在
MXML
文件的
<mx:Script>
标签中插入
as
代码,这里可以写事件处理函数,自定义事件,错误处理函数,以及任何你想写的
as
逻辑。
2.
在
ActionScript
文件定义组件类。另外考虑到组件重用,可以将此
AS
组件编译成
swc
库文件备用。
3.
在
ActionScript
文件中扩展标准组件。
4.
可以把所有的
MXML
文件
<mx:Script>
标签中的逻辑放到一个或者若干个
AS
文件中,用时可以
import
到
MXML
文件中。
上面提到在MXML文件中直接插入AS代码的方法时要用用到<mx:Script>标签,具体语法是
<mx:Script>
<![CDATA[
import mx.controls.Button;
public function myHandler():void{
var myButton:Button = new Button();
myButton.label = "label";
........
}
]]>
</mx:Script>
在这个标签里,需要注意的地方有几点。
1.
标签要成对出现。
2.
你不能在标签内定义任何的的类或者接口,因为本身当前的MXML文件就是一个类,ActionScript并没有像Java一样支持内部类定义。
3.
[CDATA[
标签主要用来告诉编译器标签内的内容不要被解释成
MXML
语法,而是
ActionScript.
4.
<mx:Script>
标签必须定义在
MXML
文件根标签的层次否则会出现编译期错误。另外
Flex2
语法上支持一个
MXML
文件中定义多个
<mx:Script>
标签。
下面举一个在MXML文件中使用AS标签的例子。
<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
//import mx.controls.Button;
public function myHandler():void{
var temp:String = "Hello Flex2";
textInput.text = temp;
}
]]>
</mx:Script>
<mx:TextInput id="textInput" creationComplete="myHandler()" />
</mx:Application>
在MXML文件中标签对象都是用id属性来标识的,一个标签对象只能有一个唯一的id.另外
需要说明的是只有类的对象才可能有id,这个id就是当前类对象的名字。比如,我们上面定义的TextInput就可以有id属性,但是当我们用mxml语法自定义一个组件类时,组件类根标签是不能设置id属性的,否则会出现编译错误。原因很好理解,因为这个组件MXML文件只是一个类定义,不是一个类对象。只有对象才可能有id,不是吗?有了id我们就可以像MXML文件内全局变量一样任意控制当前类对象的所有属性和事件处理。就像
textInput.text = temp
;
当你想索引另外的自定义类文件或者标准库文件时有可能会用到import或者include。如你想在as标签内索引Button标准组件可以用这个语法
/import mx.controls.Button
。
另外如果你想用你自定义的一个
AS
文件中的一个函数,你可以这样写
<mx:Script>
<![CDATA[
include "myactionscript.as"
]]>
</mx:Script>
2.2 Flex2
项目源文件的编译过程
首先说明一下,一个完整的Flex应用可以包括MXML文件,ActionScript文件,SWF文件,和SWC文件等。Flex编译器工作的第一个步骤是将主MXML文件以及文件内include的所有子文件转换成一个单独的ActionScript类文件。连接所有被索引(imported)的的库或自定义类文件。最后形成一个可以被部署到服务器上的swf文件。
2.3 Flex2
类库架构
Flex2
类库主要包括可视化组件类,行为类以及系统管理类。整个类库结构非常复杂。不过在我们的开发中主要用到的类包有,
1.mx.utils
包,很多有用的工具类在这里定义。
2.mx.collections
包,Flex2的数据容器类
3.mx.charts
包,各种图形组件包
4.mx.controls
包,所有的可视组件类都在这里;
5.flash.events
包,flex 事件处理类定义。
6.flash.utils
包,flash基础工具类定义,做一些底层控制时经常用到。
2.4 ActionScript
自定义组件
本小结我们将简要地介绍自定义组件的相关基础概念,在哪里创建以及怎么创建的问题。在实际的项目中我们经常需要自己定义一些组件。那么自定义组件的好处主要有两个。首先,自定义组件可以很好的隔离和封装我们通用的表现层逻辑;第二,它可以使我们建立起针对应用的组件库,使我们以后方便的重用这些组件。
自定义一个组件可以有两种表示形式,一种是利用MXML标准库标签定义组件的形式,另一种在ActionScript中定义组件类。我们都知道任何Flex组件不论是标签形式还是AS形式都最终被FlashPlayer解释成类对象。组件类定义完成后,那么我们到底该怎么以类文件为模板new一个组件对象呢?首先可以说清楚的是,我们基本上有以下4种方式初始化一个组件对象。
1.
在MXML<mx:Script>标签外,创建MXML类对象。
2.
在MXML<mx:Script>标签外,创建AS类对象。
3.
在MXML<mx:Script>标签中,创建AS类对象。
4.
在MXML<mx:Script>标签中,创建MXML类对象。
举例分析如下
比如我们继承mx.containers.Panell基础类创建一个CustomPanel自定义组件,类文件定义有两种方式分别为CustomPanelAS.as和CustomPanelMXML.mxml
CustomPanelAS.as
的代码为:
package demo.flexinaction.samples
{
import mx.containers.Panel;
public class CustomPanelAS extends Panel
{
public function CustomPanelAS(){
super();
}
}
}
Package
关键字表明了当前类所在的目录位置,这样做主要为在别的mxml或as文件中名字空间的定义提供索引。和Java的类定义很相像,要倒入类定义中需要索引的类文件 mx.containers.Panel。你不能把一个类声明成私有的,private关键字只有被用来定义类私有属性以及私有方法extends关键字说明当前类需要继承的父类。与类同名的方法CustomPanelAS()是当前类的构造器。Flex2不支持构造器的重载。super();说明调用父类的构造器。
CustomPanelMXML.mxml
文件代码如下:
<?xml version="1.0" encoding="utf-8"?>
<mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" title="CustomPanel rendered by MXML" >
</mx:Panel>
<?xml version="1.0" encoding="utf-8"?>
声明了当前mxml文件的schema以及按照utf-8标准编码。xmlns:mx= http://www.adobe.com/2006/mxml
声明了Flex2标准类库的名字空间,这样我们才能在标签中利用mx前缀引用标准类库。当然也可以定义为别的名字。或者为空就像xmlns= http://www.adobe.com/2006/mxml
,如果这样,那么在引用标准类库的时候就要这样。
<Panel xmlns:mx="http://www.adobe.com/2006/mxml" title="CustomPanel rendered by MXML" ></Panel>
类文件定义完了,我们看看Flex2中是怎么创建这个对象的。主应用文件是AdobeFlexInAction.mxml,源代码为:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
xmlns:panels="demo.flexinaction.samples.*" initialize="doInit()">
<mx:Script>
<![CDATA[
import demo.flexinaction.samples.CustomPanelAS;
import demo.flexinaction.samples.CustomPanelMXML;
private function doInit():void{
////Application
运行时(Runtime)动态创建对象
//1.
利用ActionScript类CustomPanelAS创建
var panelC:CustomPanelAS = new CustomPanelAS();
//
设置对象title属性
panelC.title = 'CustomPanel rendered by ActionScript';
//
将新创建对象加入父容器
hbox.addChild(panelC);
//2.
利用MXML组件类文件CustomPanelMXML创建
var panelD:CustomPanelMXML = new CustomPanelMXML();
//
将新创建对象加入父容器
hbox.addChild(panelD);
}
]]>
</mx:Script>
<mx:VBox id="hbox" width="407" height="414">
<!--Application
初始化时创建对象 -->
<!--
在MXML标签中利用组件类文件CustomPanelMXML创建初始化对象 -->
<panels:CustomPanelMXML id="panelA" />
<!--
在MXML标签中利用组件类文件CustomPanelAS创建初始化对象 -->
<panels:CustomPanelAS id="panelB" title="'CustomPanel rendered by ActionScript"/>
</mx:VBox>
</mx:Application>
xmlns:panels="demo.flexinaction.samples.*"
是我们自定义文件的名字空间,前缀为panels,名字空间的引入主要是为了避免大型应用的类文件名字冲突,利用名字空间,可以很好地避免这个问题。应用初始化时调用doInit()方法。Flex2标准的可视化组件都有initialize事件doInit()为事件处理函数。具体注释请参考代码中的说明。
总结:
本章主要概要地讲述了Flex2的编程模式方面的一些基础概念的理解。最后一节又小范围地解释了ActionScript自定义组件的一般过程。Flex2关键是对基本概念的理解,有了这一章的铺垫相信在后面的章节中,读者能够更加轻松的理解一些高级主题。下一篇将主要讲述Flex2真正项目实践中有可能会遇到的问题,以及目前Flex2针对特殊应用尚存的Bug以及参考解决方式。
最后,谢谢你能耐着性子继续读下去,好戏即将开始。。。。
Flex技术专栏 --by mervyn_lee