第一次大作业分析【事件篇】

来源:互联网 发布:如何设置bios网络唤醒 编辑:程序博客网 时间:2024/06/05 04:10

        前面一篇已经提到了整个项目的界面结构和实现,理论上应该没什么难度了。希望同学们都能够做到。下面介绍主要的一些事件实现思路。

        在整个项目中基本的事件主要有那么几种:按钮事件、HttpService相关事件、List相关事件和DataGrid相关事件。从易到难一个个的来分析。

        首先是最简单的按钮事件,按钮总共有那么几个:“查看购物车”按钮、“返回商店”按钮、List中的“加入购物车”按钮和DataGrid中的删除按钮。

        1、“查看购物车”按钮和“返回商店”按钮

        这两个按钮主要实现它们的Click事件,右击按钮可以生成自动事件处理函数【PS:大家要养成良好的编程习惯,就是在界面上放置好控件后首先要修改该控件的ID,这里假定这两个按钮的ID分别是btnCartView和btnShop】。函数代码就是用来改变当前的状态为相应的状态名。现在就两个状态视图,一个是默认的State1,一个是新建的cartView。点击“查看购物车”切换到cartView,点击“返回商店”切换回State1。本来这样就可以了。但是我们考虑到List和DataGrid的数据加载问题,所以做了点改变,什么改变呢?就是List是首先显示的界面,需要绑定到商品列表,而且整个数据是一次绑定永不更改,所以在整个Application初始化时就绑定好了数据。但是DataGrid的数据是会变化的,所以在Application初始化时不做绑定,但是在点击“查看购物车”时绑定数据显示最新的购物车信息。那么“返回商店”按钮的点击事件还是老样子,就是改变当前的状态,但是“查看购物车”按钮的点击事件就是除了改变当前的状态之外,还要实现向服务器端请求最新购物车信息并加载到DataGrid上。具体实现后面会提到,目前先预留这个功能(预留的意思就是你在这个事件里用注释的方式写上以后要实现的功能,例如://这里实现远程数据获取)。

        2、HttpService相关事件

        在第1点中我们已经提到要从远程服务器中获取数据绑定到相应控件,主要两个控件需要绑定,一个是List,一个是DataGrid。前面也提到List的绑定是在Application初始化时操作,DataGrid的绑定是在点击“查看购物车”按钮时操作。绑定之前当然首先需要从服务器端获取到数据,那么如何将FLEX与远程服务器连接起来呢,方法有很多,我们这里使用的是HttpService这个不可见的控件对象。

        那么首先来介绍下HttpService【官方介绍】。 这里简单的说下,就是提供一个http相关的服务,方便Flex与远程URL指定的文件进行连接,可以传递参数也可以获取返回信息。主要调用的方法是send(可选择带参数send也可以无参数send),主要设置的属性是method、url和resultFormat,主要实现的事件是result。

       正式开始:List的数据绑定前面说了是在Applicaton初始化时操作,那么Application初始化会激发什么事件呢?很多,这里使用creationComplete事件。在该事件中我们发送带参数的请求到远程服务器。那么我们发送给谁呢?创建一个HttpService对象,如下所示:

<s:HTTPService id="goodsListService" url="http://localhost/xmlAction.aspx" resultFormat="e4x" result="handleGoodsResult(event)"/>
        这个就表示我们创建了一个名为goodsListService的HttpService,它将连接到localhost下的xmlAciton.aspx文件,然后当捕获了远程连接的成功返回后会激发result事件,从而调用处理函数handleGoodsResult函数,远程连接的返回值格式是e4x类型。这里要注意的是像HttpService这种不可见的控件对象是要放在<fx:Declarations>节点里面的

        然后在前面提到的creationComplete事件处理函数handleCreationComplete中,我们就可以写如下代码:

var params:Object=new Object();//创建一个用来存储发送参数的Object对象params.mode="readGoods";//参数就一个,参数名为mode,参数值为readGoodsgoodsListService.method="post";//请求远程URL的方法是postgoodsListService.send(params);//发送带参数的请求
        这样我们就把一个带参数的请求发送到了url指定的xmlAction.aspx页。然后成功返回后调用result事件处理函数handleGoodsResult:
goodItems=new XMLListCollection(event.result.goodItem);
        其中这个goodItems是一个XMLListCollection类型的全局变量
[Bindable]private var goodItems:XMLListCollection;
        为什么要在前面加上[Bindable],因为这个变量我们需要用它来做List控件数据源dataProvide,所以应该是一个会自动更新的可绑定类型,就要加[Bindable]。

        然后我们就可以将List的dataProvide属性设置为该变量:

<s:List id="listGoods" includeIn="State1" x="0" y="0" width="100%" height="249" borderVisible="false" <strong><span style="color:#FF0000;">dataProvider="{goodItems}"</span></strong> itemRenderer="views.viewGoodsList">
        这样在Application初始化完成后就能连接到远程服务器,并根据传递的mode参数获取返回值为一个XMLListCollection对象作为List的数据源。然后在List的项呈现器里的每个控件上分派各个节点名,如{data.theID}就能将XML文件中的每个商品节点下的theID节点值显示在该控件上。

        OK,绑定成功。

        同理,在点击“查看购物车”按钮事件处理函数中,也利用HttpService向远程服务器文件发送请求,获取返回值后作为DataGrid的dataProvide。为了避免两者混淆我们另外建了一个HttpService,前面那个用来操作商品列表文件,新建的这个用来操作购物车列表文件。

<s:HTTPService id="cartInfoService" url="http://localhost/flexAPP/xmlAction.aspx"  resultFormat="e4x" result="handleCartInfoResult(event)"/>
var params:Object=new Object();params.mode="readCartInfo";cartInfoService.method="post";cartInfoService.send(params);
cartInfoList = new XMLListCollection( event.result.cartItem );
[Bindable]private var cartInfoList:XMLListCollection;
<s:DataGrid id="dg" includeIn="cartView" x="0" y="0" width="100%" height="272" <strong><span style="color:#FF0000;">dataProvider="{cartInfoList}"</span></strong>>    <s:columns>        <s:ArrayList>            <s:GridColumn dataField="theID" headerText="商品编号"></s:GridColumn>            <s:GridColumn dataField="theName" headerText="商品名称"></s:GridColumn>            <s:GridColumn dataField="totalPrice"headerText="商品总价"></s:GridColumn>            <s:GridColumn dataField="totalNum" headerText="商品数量"></s:GridColumn>            <s:GridColumn editable="false" headerText="操作" itemRenderer="views.viewDGActionCol"></s:GridColumn>        </s:ArrayList>    </s:columns></s:DataGrid>

        那么到这里,我们就利用了两个HttpService实现了List和DataGrid的数据绑定,一个绑定在初始化时进行,一个绑定在点击“查看购物车”按钮时进行。

        3、List相关事件

        在List中我们还需要实现点击“加入购物车”按钮事件。本来这个按钮是属于List的,我们可以直接操作List的Click事件,但是这样的话点击List中某个商品的任意位置(不一定点到按钮上)都会激发这个事件,而我们点击这个按钮对List的显示没有任何更改操作,所以我们可以直接在List的项呈现器文件中定义按钮事件就行了。但是因为该按钮事件涉及到需要传递当前选中的商品信息到远程服务器,所以在List的项呈现器文件中又要定义个HttpService控件对象,过程类似前面的绑定,但是需要传递多个参数过去:

<s:HTTPService id="goodsListService" url="http://localhost/flexAPP/xmlAction.aspx" resultFormat="e4x" result="handleGoodsResult(event)"/>
        “加入购物车”按钮点击事件:

var goodID:String=lbID.text;//获取当前商品的IDvar goodName:String=lbName.text;//获取当前商品的名称var goodIMG:String=lbIMG.text;//获取当前商品的图片文件名var goodPrice:String=lbPrice.text;//获取当前商品的价格var params:Object=new Object();//创建一个用来存储发送参数的Object对象params.mode="writeGoods";//参数1,参数名为mode,参数值为readGoodsparams.goodID=goodID;//参数2,参数名为goodID,参数值为goodID变量值params.goodName=goodName;//参数3,参数名为goodName,参数值为goodName变量值params.goodIMG=goodIMG;//参数4,参数名为goodIMG,参数值为goodIMG变量值params.goodPrice=goodPrice;//参数5,参数名为goodPrice,参数值为goodPrice变量值goodsListService.method="post";//post方式发送请求goodsListService.send(params);//发送带参数的请求
        这里要注意的就是有多个参数需要发送到服务器,那么这些参数值哪里来,就是在这个List的项呈现器里用控件绑定的数据:有些控件绑定数据后需要显示出来,那不需要做其他额外操作,但是有些控件绑定数据后不需要显示,那么就要设置隐藏,在这里隐藏某个控件仅仅设置visible为false不够,还要设置一个includeInLayout为false。

        最后远程服务器返回成功后调用result处理函数:

if(event.result.toString().indexOf("writeOK",0)==0)//如果远程服务器的返回结果是writeOK(这个writeOK的值是有服务器端代码指定的,可以自定义){    Alert.show("添加成功!"); //那么就弹出“添加成功”的对话框。}
        如果点了“加入购物车”按钮后会影响到该按钮的父容器List,那么就需要做额外的事情,但是现在这里不需要。

        4、DataGrid相关事件

        在前面【界面篇】中有提到DataGrid上需要实现编辑和删除的操作,编辑相对简单点,首先根据【界面篇】中的介绍设置好商品数量的可编辑状态,然后就可以去找合适的事件来实现了。在spark的DataGrid控件上有个很方便的事件:gridItemEditorSessionSave,专门用来做编辑后保存的。我们来实现该事件的处理函数dg_gridItemEditorSessionSaveHandler(函数名是自动生成的,由于DataGrid的ID命名个人习惯不同,所以函数名可能不同)。

var xmlNode:XMLList=new XMLList(dg.selectedItem);//定义一个XMLList类型的变量来接收当前选中项(编辑某项必须先选中该项的)var goodID:String=xmlNode.theID;//然后获取该项的商品IDvar goodNum:String=xmlNode.totalNum;//获取该项的编辑后的商品数量var params:Object=new Object();//定义参数对象params.mode="editCartInfo";//设置参数1,参数名mode,参数值editCartInfoparams.goodID=goodID;//设置参数2,参数名goodID,参数值goodID变量值params.goodNum=goodNum;//设置参数3,参数名goodNum,参数值goodNum变量值cartInfoService.method="post";//post发送cartInfoService.send(params);//发送带参数请求
        服务器端成功返回后执行result事件处理函数,这个函数在第2点中已经实现过一次了,所以我们要进行补充:

        原来的代码:

cartInfoList = new XMLListCollection( event.result.cartItem );
        修改后的代码:

if(event.result.toString()=="editOK"){    Alert.show("修改成功!");    refreshIT(event);}else    cartInfoList = new XMLListCollection( event.result.cartItem );
        也就是说如果服务器端的返回值是editOK(由服务器端代码指定,可自定义),表示当前编辑成功,那么就显示“修改成功”对话框,并刷新DataGrid,否则的话就获取购物车信息,绑定到DataGrid,那么为什么不这样写呢:

if(event.result.toString()=="editOK"){    Alert.show("修改成功!");}cartInfoList = new XMLListCollection( event.result.cartItem );
        这样写的话就变成,修改成功的情况下,把editOK这个文本字符串作为DataGrid的数据源,这样就不对了。所以我们需要在修改成功的情况下自定义个refreshIT函数来刷新DataGrid的数据源:

var params:Object=new Object();params.mode="readCartInfo";cartInfoService.method="post";cartInfoService.send(params);
        refreshIT函数的代码和点击“查看购物车”按钮Click事件处理函数代码类似。到这里我们的编辑事件也完成了。接下来就剩下最后一个删除了。删除功能想象貌似挺简单的,不就和List中的“加入购物车”按钮差不多嘛,你错了,真的错了,这就是个坑,一个比较深的坑。爬出来挺花时间的,幸好我不算矮,也还挺厚的,有我垫底,你们爬的会快点。

        言归正传,我们来看重中之重。

        List中的“加入购物车”按钮点了之后对List是不产生任何影响的,里面的数据是不用刷新的,但是DataGrid里的“删除”按钮不同,点了之后要重新加载DataGrid的数据源。所以问题来了,“删除”按钮是放在DataGrid的项呈现器MXML文件中的,而前面定义的重新加载DataGrid的自定义函数refreshIT是放在主MXML文件中的,如何在外部文件中调用主文件中的函数就待攻克的难关了。

        首先我们来看项呈现器里的“删除”按钮Click事件处理函数:

var goodID:String=lbID.text;//获取删除按钮所在商品的goodID的值(利用一个隐藏的Lable存放goodID的值)var params:Object=new Object();//声明参数对象params.mode="delCartInfo";//设置参数1,参数名mode,参数值delCartInfoparams.goodID=goodID;//设置参数2,参数名goodID,参数值goodID变量值goodsListService.method="post";//post发送goodsListService.send(params);//带参发送请求
        当然要事先定义好HttpService控件对象,这些代码应该说已经比较熟悉了,应该没什么大问题,然后成功返回后实现result事件处理函数:

if(event.result.toString().indexOf("delOK",0)==0)//如果返回值是delOK(服务器端代码指定,可自定义){    var e:Event = new Event("refreshDG",true);//定义一个新的事件对象,重点,下面详述    var flag:Boolean=this.dispatchEvent(e);//dispatch这个事件对象,重点,下面详述    Alert.show("删除成功!");//弹出“删除成功”对话框,没难度}
        这段代码里就两行有问题,1、定义一个新的事件对象,2、然后dispatch出去(类似于广播模式,我在广播里喊一声,大家听着,谁的娃掉了,来捡)。

        第一个问题:定义新的事件对象,语法格式没问题,new一个对象,关键是参数,第一个参数表示该事件的类型,第二个参数表示该事件是否允许参与冒泡流程,第一个名称没问题,反正是自定义个类型名称而已,第二个什么叫冒泡流程,简单的理解就是池塘底的淤泥里发酵产生一个气泡,然后往上升,升啊升,一级级往上,突然中间出现一个吃泡泡的东西把它吃掉,ok,问题解决。

        第二个问题:什么叫dispatch出去,这个就要和冒泡关联起来了,就是如果允许冒泡,那么就会出出来上面说的那个吃泡泡的东西,如果不允许,打死它都不出现,问题就解决不了。

        普通青年这样理解:【参与冒泡模式】我创建了一个事件对象,但是目前我这个级别处理不了,然后我就把这个事件告诉其他模块,快来帮我处理快来帮我处理,这是某个模块挺好心的一致在关注我,然后他就发现了并处理掉了,ok,问题解决。

【不参与冒泡模式】我创建了一个事件,但是目前我这个级别处理不了,但是我觉得当前应用里其他模块应该会帮我处理就没去请求帮助,然后这个事件就永远搁置了。

        文艺青年这样理解:【参与冒泡模式】我是郭敬明,有个氢气球,没抓牢,往上飘,我大喊我的气球飞了,边上有个姚明,他抓住了,还给我,问题解决。【不参与冒泡模式】我是郭敬明,有个氢气球,没抓牢,往上飘,我默默的看着边上在忙的姚明,他没理我,气球飞了。

        2B青年这样理解:【有奖征集,回复写出答案,大家投票表决,前三名允许一次实验补交,或屏蔽一次实验借鉴。】

        有个要注意的地方是我这边定义了一个名为refreshDG的新事件类型,但是这个事件类型是我自定义的,系统不认,需要我们手动进行事件注册,所以在当前文件的全局位置注册下:

[Event(name="refreshDG", type="flash.events.Event")]
        好了我的新事件类型已经注册、定义并发送出去了,但是谁来接收呢?我们这里当然应该是主文件,不过你都说只是应该了,主文件并没有这个义务来关注你一个小小的外部文件,所以我们必须和主文件打好关系,让主文件时刻保持对我这个外部文件的自定义事件的监听。因此在主文件里我们需要添加一个事件监听,加在什么地方,当然是主文件的Application初始化的时候就来监听了,也就是在creationComplete事件的处理函数里:

this.addEventListener("refreshDG",refreshIT);
        这就表示我的主文件Application初始化之后就开始对refreshDG这个事件进行监听,一旦这个事件被触发,立刻调用refreshIT来处理。

        OK,事件篇就这样结束了……是不是很Happy?Go to hell我想才是大家的心声……

        未完待续,下一篇【服务器端篇】



0 0
原创粉丝点击