`

Flex中使用模块Module的例子

    博客分类:
  • Flex
阅读更多

首先是应用的代码, 在应用中使用 <mx:ModuleLoader >来加载模块
<?xml version="1.0"?>
<!-- modules/URLModuleLoaderApp.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" viewSourceURL="srcview/index.html">

    
<mx:Panel
    title
="Module Example"
    height
="90%"
    width
="90%"
    paddingTop
="10"
    paddingLeft
="10"
    paddingRight
="10"
    paddingBottom
="10"
    
>
    
    
<mx:Label width="100%" color="blue"
    text
="Select the tabs to change the panel."/>
    
    
<mx:TabNavigator id="tn"
    width
="100%"
    height
="100%"
    creationPolicy
="auto"
    
>
    
        
<mx:VBox id="vb1" label="Column Chart Module">
        
            
<mx:Label id="l1" text="ColumnChartModule.swf"/>
            
<mx:ModuleLoader url="ColumnChartModule.swf"/>
        
        
</mx:VBox>
        
        
<mx:VBox id="vb2" label="Pie Chart Module">
        
            
<mx:Label id="l2" text="piehchartmodule.swf"/>
            
<mx:ModuleLoader url="piechartmodule.swf"/>
        
        
</mx:VBox>
        
        
<mx:VBox id="vb3" label="Line Chart Module">
        
            
<mx:Label id="l3" text="linehchartmodule.swf"/>
            
<mx:ModuleLoader url="linechartmodule.swf"/>
        
        
</mx:VBox>
    
    
</mx:TabNavigator>
    
</mx:Panel>

</mx:Application>

 

在这个应用中主要是一个TagNavigator, 里面有三个标签页. 每个标签页加载一个模块.
下面是其中一个模块的代码:
<?xml version="1.0"?>
<!--ColumnChartModule.mxml -->
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%" >

    
<mx:Script><![CDATA[
    
        
import mx.collections.ArrayCollection;
        [Bindable]
        
public var expenses:ArrayCollection = new ArrayCollection([
        
{Month:"Jan", Profit:2000, Expenses:1500},
        
{Month:"Feb", Profit:1000, Expenses:200},
        
{Month:"Mar", Profit:1500, Expenses:500}
        ]);
        
    ]]
></mx:Script>
    
    
<mx:ColumnChart id="myChart" dataProvider="{expenses}">
    
        
<mx:horizontalAxis>
        
            
<mx:CategoryAxis
            dataProvider
="{expenses}"
            categoryField
="Month"
            
/>
            
        
</mx:horizontalAxis>
        
        
<mx:series>
        
            
<mx:ColumnSeries
            xField
="Month"
            yField
="Profit"
            displayName
="Profit"
            
/>
            
            
<mx:ColumnSeries
            xField
="Month"
            yField
="Expenses"
            displayName
="Expenses"
            
/>
            
        
</mx:series>
    
    
</mx:ColumnChart>
    
    
<mx:Legend dataProvider="{myChart}"/>
    
</mx:Module>

最后, 应用和三个模块一共会生成4个SWF. 一般来说, 应用使用延迟加载策略. 也就是说, 如果你打开应用后, 从来都不使用其中的某个模块, 那个这个模块永远不会被加载. 这次做的好处是, 加快了第一次打开应用的速度, 但随之而来的缺点就是, 第一次打开使用某个功能, 需要加载模块时, 会需要一点等待的时间.

 

如果你没有看过Roger Gonzalez的Blog中关于模块(Module)的文章,那么你应该去那里了解一下Flex 2这个特性背后的细节和想法。这里我不想过多地探讨为什么要这样,而是想要给大家展示一个使用了模块(Module)的简单的Flex程序,你可以从中获得启示。

示例源码

你可以下载关于这个例子的压缩文件:点击这里下载。

模块(Modules)

模块(Module)是创建大型Flex应用程序的一个解决方案,它允许你将你的用户接口分割成许多分散的有各自用途的小块。例如(下面出自Flex 2的文档),一个保险公司可能有数百个表单——针对于各个领域的,针对各种请求类型,以及针对各种应用等等。创建一个包含所有这些表单的Flex应用程序将会产生一个巨大SWF文件,还会有不少问题:
 •应用程序越大开发过程越复杂;
 •应用程序越大测试过程越复杂;
 •应用程序越大部署过程越复杂;
 •SWF文件越大加载时间越长

我的示例程序基于Flex 2文档中的一个程序,但是我将它做了一些更改来说明几个常见的问题。这个例子展示了一个主程序和其它三个共享公有数据的模块(Module)。

其中一个设计要素是一个接口的使用,这个接口实质上是接口实现者和使用者之间的一个契约。这个例子将会说明我所说的意思。模块(Module)的接口部分虽然不是必须的但是却可以大大简化以后的开发和维护。比如,如果开发人员有一个小组负责报告部分,另一个小组负责图表部分,如果它们一开始用了接口,那么只要有需要,接口的实现就可以做足够多的变形而不会影响到工程结果。接口在模块(Module)中还扮演另外一个角色,我在下文中将会揭示这点。

模块(Module)是以<mx:Module>代替<mx:Application>作为根标签的MXML文件(或ActionScript文件)。你可以将带有<mx:Module>标签的作为一个程序来看,但是它不能运行。

这个示例有一个主程序文件以及带有一个接口的两个模块。打开主程序文件你会看到:



程序代码
<mx:Panel x="10" y="41" width="169" height="500" layout="absolute" title="Modules">
     <mx:Text x="10" y="24" text="Check a module to load it; uncheck to unload it" width="129"/>
     <mx:RadioButton x="10" y="97" label="None" selected="true"
                         click="removeModule()"/>
     <mx:RadioButton x="10" y="123" label="Chart"
                        click="removeModule();loadModule('ChartModule.swf')"/>
     <mx:RadioButton x="10" y="175" label="Table"
                       click="removeModule();loadModule('GridModule.swf')"/>
</mx:Panel>

<mx:Panel x="187" y="41" width="500" height="500" layout="absolute" title="Module: {moduleName}">
      <mx:ModuleLoader id="currentModule" ready="readyModule(event)"
                      width="100%" height="100%" />
</mx:Panel>


第一个Panel包含了控制示例中模块(Module)加载和卸载的RadioButtons。第二个Panel是使用<mx:ModuleLoader>标签加载模块(Module)的地方。注意那个id为currentModule的ModuleLoader,它有一个关于ready事件的事件处理器。当模块SWF文件加载了足够多可以开始使用的时候,ModuleLoader 就会分派ready事件(或者说ModuleEvent.READY)。

这里有一个readyModule函数,它在<mx:Script>块中:



程序代码
private function readyModule( event:ModuleEvent ) : void
{
      var ml:ModuleLoader = event.target as ModuleLoader;

     var ichild:IExpenseReport = ml.child as IExpenseReport;
     if( ichild != null ) {
              ichild.expenseReport = expenses;
     }
}


注意ModuleLoader的child属性是如何转换为IExpenseReport类的。IExpenseReport是一个所有模块(Module)都实现了的接口。只要每个模块都实现了这个接口,它就可以很容易适应于应用程序。换句话说,想象一下当你需要创建另一个表单或者报告的时候它的用途。并不需要更改主程序为新模块添加IF语句,你只要在新模块中实现IExpenseReport接口它就可以在程序中完美地运行。

IExpenseReport接口是:



程序代码
public interface IExpenseReport
{
     function set expenseReport( ac:ArrayCollection ) : void;
}


每个模块(Module)都实现这个接口,定义各自的名为expenseReport的set函数。下面是ChartModule的根标签和接口IExpenseReport的实现:



程序代码
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml"implements="IExpenseReport"
           layout="vertical"
           percentWidth="100" percentHeight="100" >
    <mx:Script><![CDATA[
          import mx.collections.ArrayCollection;
          [Bindable] public var expenses:ArrayCollection;

          public function set expenseReport( ac:ArrayCollection ) : void
          {
                expenses = ac;
           }
    ]]></mx:Script>
...
</mx:Module>


让我们回到主程序,RadioButton的click事件会卸载任何当前已加载的模块然后加载一个新的模块。下面是ChartModule的RadioButton标签:



程序代码
<mx:RadioButton x="10" y="123" label="Chart" click="readyModule('ChartModule.swf')"/>


这个click事件会调用上面列出的readyModule事件。

编译并运行程序

如果你使用了Flex Builder 2,请确定更改了项目的Properties将模块(Module)作为"Applications"包含进来。这样Flex Builder 2回将它们编译进SWF文件并且放进bin文件夹中。

Flex Builder注意:要创建一个使用模块(Module)的工程,请使用工程的Properties将模块文件作为"Applications"。这会使得他们被编译进SWF文件。

一旦SWF文件被创建你就可以运行主程序并点击RadioButtons在模块(Module)之间切换。

Flex Builder注意:Flex Builder并不会保存任何关于模块(Module)和主程序的从属信息。只要你对一个模块(Module)作了更改,你就可能需要重新编译主程序或其它从属的模块(Module)。

将SWF文件最优化

如果你查看一下主程序的SWF文件和模块(Module)的SWF文件的话,你会发现它们的大小差不多。这就说明,模块的SWF和主程序SWF中有很多同样的组件定义。

Flash Player并不会保存元件(symbol)的副本。例如,如果主程序有一个Button组件而一个模块(Module)也有一个Button组件,Flash Player就不会从模块中加载Button了,因为它已经在主程序中有定义了。

使用-link-report=report.xml编译主程序,这样会创建一个链接到主程序的包含所有元件信息的文件。然后在编译模块(Module)的时候会使用那个report.xml文件。



程序代码
mxmlc -load-externs=report.xml ChartModule.mxml


当ChartModule被编译的时候,所有在report.xml文件中列出的元件将会在它的SWF中省略。当我不使用report.xml文件编译ChartModule.swf的时候,它的大小是202K。而当我使用report.xml文件的时候,SWF的大小只有68K。这大大减少了模块(Module)的加载时间。

在文章的开始将到模块(Module)的时候,我提过接口有另一个作用。假设你没有使用接口而是在主程序中引用模块的类。当你运行link-report的时候,你的模块类将会出现在report.xml中。当你使用使用link-report编译模块(Module)的时候你的模块并不会包含在它自己的SWF中!起初这并不会成为一个问题,尽管主程序由于包含了模块的定义而变得很大。然而,当你更改你的模块的时候发生了什么才是重要的。如果你没有重新编译主程序,你主程序的SWF文件将会包含模块(Module)旧的定义——而不是你已经更改过的。



程序代码
mxmlc -link-report=report.xml Main.mxml
mxmlc -load-externs=report.xml ChartModule.mxml
// etc.


如果你决定使用这个技术来减小模块(Module)的大小,那么就使用接口来确保终端用户使用的总是模块(Module)的最新版本。

Flex Builder注意:Flex Builder在一个工程里没有办法做到这些。如果你确定你将要创建一个使用模块(Module)的工程,可以考虑一下将公共的类和接口(包括event类)放到一个SWC(Flex Library Project)中然后将模块(Module)分离到它们各自的工程里。

或者,你可以将所有东西创建为一个单一的Flex工程,然后将最优化作为一个产品化前或测试前的部署步骤在Flex Builder之外进行。

 

Flex2.01之后提供了modules模块化开发包,开发者可以将程序的某些模块编译成swf,在需要的地方load进去,实现模块化的开发。

现在问题来了,每个module会被编译成swf,在一个Application中,module之间该如何通信交互呢。

通常来说,在一个swf中,组件间的交互通信可以直接addEventListener 和dispatchEvent来完成事件的传递。当然这样标准的做法也适用于module。理解在AS 3.0中事件遵循向上传递的原则,那么下面的工作就好做了。

例如,在一个Application中分别由ModuleLoaderA和ModuleLoaderB加载了两个module,分别为moduleA和moduleB,其中A需要向B传递数据。事件的传递就应该是这样的:moduleA --> ModuleLoaderA --> Application --> ModuleLoaderB --> moduleB。
1. 首先当然先要定义一个事件,那么在moduleA里应该由this.parent.parent来dispatchEvent(事件),this.parent即加载moduleA的ModuleLoaderA,那么this.parent.parent即Application;
2. 在Application中,由ModuleLoaderA来addEventListener(事件),即侦听了由moduleA传上来的事件,侦听到之后再由ModuleLoaderB负责dispatchEvent(事件)。
3. 在moduleB里,this.parent.parent.addEventListener(事件),这样就侦听了由ModuleLoaderB传递的事件。

其实在module里,使用this.systemManager.addEventListener/dispatchEvent也可以完成事件的传递,但是如果一个module里用this.systemManager,而另一个module里使用this.parent.parent却不能传递事件,systemManager并不等于application,systemManager.document才是application,也就是说用systemManager的话必须两者都用,用parent的话也可以使用systemManager.document。不明白的朋友可以仔细阅读Flex的帮助文档。

分享到:
评论

相关推荐

    flex 模块化modules源码例子

    2. **Flex模块化机制**:在Flex中,模块(Module)是可以通过`mx:Module`标签定义的独立的SWF文件。它们在运行时按需加载,有助于减少初始加载时间,并且可以动态地添加或移除模块。使用模块可以优化性能,因为不是...

    flex中moduleLoader加载module时传递参数源代码

    在Flex开发中,`ModuleLoader` 是一个关键组件,它允许开发者动态地加载MX模块(即Flex模块,独立的SWF文件)。`ModuleLoader` 的主要功能是将模块的加载过程与应用程序的其余部分分离,这有助于实现代码的模块化和...

    flex一个动态添加卸载Module的例子

    在这个例子中,我们将深入探讨如何在Flex中动态添加和卸载Module。 模块(Module)是Flex应用程序的一个重要组成部分,它允许我们将大项目分解为更小、更易于管理的部分。动态加载和卸载Module是优化应用程序性能和...

    Adobe官方Flex3 Module模块设计经典资料(附源代码)

    在Flex3的Module模块程序设计中,在Google中进行了大量的资料查找,综合比较各个资源后,将我认为最有价值的资料放在这里(全英文的)。 下载包中包括: 1、Adobe Creating Mudule Application.pdf 2、相似例子的源...

    Flex 模块化应用程序开发

    例如,在这个例子中定义了一个名为`IExpenseReport`的接口,该接口中声明了一个`setexpenseReport`方法,用于接收数据集合并更新模块内的视图。 4. **模块定义**:每个具体的模块都需要实现`IExpenseReport`接口。...

    flex modules 中英文版

    模块(Module)是创建大型Flex应用程序的一个解决方案,它允许你将你的用户接口分割成许多分散的有各自用途的小块。例如(下面出自Flex 2的文档),一个保险公司可能有数百个表单——针对于各个领域的,针对各种请求...

    Flex--used-in-the-example-module.zip_FlashMX/Flex源码_Flex_

    **示例“Flex中使用模块Module的例子.mht”:** 这个文件很可能是一个包含了详细步骤和代码实例的教程,教你如何在Flex项目中创建和使用模块。MHT是一种单个文件的Web页面存档格式,通常包含HTML、图像和其他相关...

    Flex精通_66013.rar

    5. **动态添加卸载Module的例子**:Flex支持模块化开发,允许在运行时动态加载和卸载模块。`一个动态添加卸载Module的例子.rar`提供了具体的实例,讲解如何使用Flex的ModuleLoader组件来实现这一功能,这对于构建...

    FLEX弹出框特效,很好很强大

    1. **Flexbox基础**:Flexbox,全称为“Flexible Box Layout Module”,是CSS3的一个模块,设计用于处理容器内元素的一维布局,如行或列。通过Flexbox,我们可以轻松实现弹性布局,包括自适应大小、对齐方式以及在...

    flex页面跳转及数据绑定

    在例子中,它会打开一个新的页面,而不是在当前Flex应用程序中进行切换。 3. **ExternalInterface调用**:利用Flash Player与JavaScript的交互能力,通过调用ExternalInterface.call方法,可以执行JavaScript中的...

    Flex ApplicationDomain

    在Flex中,通常在处理模块(Module)时会用到ApplicationDomain。模块可以看作是独立的应用程序,它们有自己的ApplicationDomain,可以加载不同的类集,这使得模块化开发更加灵活,也便于版本控制和更新。 举个例子...

    Some technical documents of Parsley.

    压缩包中的文件“Flex4以及Parsley多模块架构例子 – IT妖怪.mht”是一个MHT(单个文件网页)文档,可能包含了关于如何在Flex 4环境中使用Parsley实现多模块架构的教程。Flex 4是Adobe Flex框架的一个版本,引入了新...

    Parsley Hello World 实例工程源代码

    8. **模块(Module)支持**:Parsley支持Flex模块化开发,可以在需要时加载或卸载模块,这对于大型应用程序的性能优化和代码组织非常有用。 9. **单元测试**:Parsley的DI特性使得单元测试变得容易,因为我们可以...

    可以运行的puremvc的登陆实例.

    在这个例子中,可能会有一个名为`LoginProxy`的类,用于存储和操作用户输入的登录信息。 2. **视图(View)**:视图负责展示用户界面和收集用户输入。在登录实例中,视图可能包含一个用户名文本框、密码文本框和...

    Instantiating LPMs in Verilog

    在Verilog语言中,"Instantiating LPMs in Verilog" 是指在设计中使用Altera的逻辑元素模块(LPMs,Logic Primitive Modules)来创建硬件实例的过程。本例中,我们关注的是如何实例化一个名为LPM_RAM_DQ的参数化...

    (KinetisK60)FTM输入捕捉中断4.pdf

    在本文中,我们将深入探讨基于Kinetis K60微控制器的FTM(FlexTimer Module)输入捕捉中断的实现。这个例子展示了如何配置FTM模块来实现PWM输出以及设置输入捕捉中断,同时利用PIT(Periodic Interrupt Timer)进行...

    uni-app跨平台移动应用开发教程

    可以在模版中使用简单的JavaScript表达式。 **5.5 计算属性** 计算属性提供了一种更高效的方式来获取和处理数据。 #### 六、生命周期 **6.1 VUE实例生命周期** 描述了Vue实例从创建到销毁的整个过程。 **6.2 ...

    angular-playground:角度基础示例

    在`angular-playground`中,你可以看到如何定义主模块(AppModule)以及如何导入其他模块。 2. **组件(Components)**:组件是Angular应用的基石,它们负责显示UI并处理用户交互。通过查看项目中的组件文件,你...

Global site tag (gtag.js) - Google Analytics