http://www.robotlegs.org/
或以下這本電子書:
http://www.wowebook.pro/book/actionscript-developers-guide-to-robotlegs/
寫一個很簡單的 login 範例。
主畫面,包含了 login 與 logon 兩個 state;這份 view component 同時包含了簡單的事件 用來向 Mediator 傳達使用者的操作。
/HelloRobotlegs.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:ben="idv.ben.*"
minWidth="955" minHeight="600">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
import idv.ben.event.ViewCompEvent;
[Bindable]
public var userName:String = "";
protected function btnSubmit_clickHandler(event:MouseEvent):void
{
this.dispatchEvent(new ViewCompEvent(ViewCompEvent.LOGIN_CLICKED));
}
protected function btnLogout_clickHandler(event:MouseEvent):void
{
this.dispatchEvent(new ViewCompEvent(ViewCompEvent.LOGOUT_CLICKED));
}
]]>
</fx:Script>
<s:states>
<s:State name="State1"/>
<s:State name="login"/>
<s:State name="logon"/>
</s:states>
<fx:Declarations>
<ben:AppContext contextView="{this}" />
</fx:Declarations>
<s:Label text="Robotlegs Example" fontSize="24"/>
<mx:Form width="300" includeIn="login">
<mx:FormHeading label="login"/>
<mx:FormItem label="UID:">
<s:TextInput id="txtUID"/>
</mx:FormItem>
<mx:FormItem label="PWD:">
<s:TextInput id="txtPWD"/>
</mx:FormItem>
<mx:FormItem>
<s:Button label="Submit" id="btnSubmit" click="btnSubmit_clickHandler(event)"/>
</mx:FormItem>
</mx:Form>
<s:Label includeIn="login" text="error message" id="txtErrorMessage" color="#FF0000"/>
<s:Label includeIn="logon" text="Hello, {userName}" fontSize="36"/>
<s:Button includeIn="logon" label="Logout" id="btnLogout" click="btnLogout_clickHandler(event)"/>
</s:Application>
Context,類似 PureMVC 的 Facade,在此註冊、或建立一些對照表。
/idv/ben/AppContext.as
package idv.ben
{
import flash.display.DisplayObjectContainer;
import idv.ben.controller.LoginCommand;
import idv.ben.controller.LoginSuccessCommand;
import idv.ben.controller.LogoutCommand;
import idv.ben.event.MediatorLoginEvent;
import idv.ben.event.MediatorLogoutEvent;
import idv.ben.event.ServiceLoginedEvent;
import idv.ben.model.AppModel;
import idv.ben.view.AppMediator;
import org.robotlegs.mvcs.Context;
import idv.ben.service.AppService;
public class AppContext extends Context
{
public function AppContext(contextView:DisplayObjectContainer=null, autoStartup:Boolean=true)
{
super(contextView, autoStartup);
trace(this, "AppContext()", "contextView=" + contextView);
}
override public function startup():void{
trace(this, "startup()");
//service
this.injector.mapSingleton(AppService);
//model
this.injector.mapSingleton(AppModel);
//view
this.mediatorMap.mapView(HelloRobotlegs, AppMediator);
//controller
this.commandMap.mapEvent(MediatorLoginEvent.LOGIN, LoginCommand);
this.commandMap.mapEvent(MediatorLogoutEvent.LOGOUT, LogoutCommand);
this.commandMap.mapEvent(ServiceLoginedEvent.SERVICE_LOGINED, LoginSuccessCommand);
super.startup();
}
}
}
先談到 Model,僅僅用來存放一些資料,這裡我用來存放 "是否登錄" 與 "登錄成功後得到的 user name"。
/idv/ben/model/AppModel.as
package idv.ben.model
{
import idv.ben.event.ModelEvent;
import org.robotlegs.mvcs.Actor;
public class AppModel extends Actor
{
private var _loginStatus:Boolean = false;
public function get loginStatus():Boolean
{
return _loginStatus;
}
public function set loginStatus(value:Boolean):void
{
_loginStatus = value;
this.dispatch(new ModelEvent(ModelEvent.LOGIN_STATUS_CHANGED));
}
private var _userName:String = "";
public function get userName():String
{
return _userName;
}
public function set userName(value:String):void
{
_userName = value;
}
}
}
再談到 Service,主要是用來與外界溝通資料用的。
/idv/ben/service/AppService.as
package idv.ben.service
{
import flash.utils.setTimeout;
import idv.ben.event.ServiceLoginErrorEvent;
import idv.ben.event.ServiceLoginedEvent;
import org.robotlegs.mvcs.Actor;
public class AppService extends Actor
{
public function login(uid:String, pwd:String):void{
if(uid == "" || pwd == "")
fooLoginError("input error");
else if(uid != "abc")
setTimeout(fooLoginError, 2000, "wrong uid");
else if(uid == "abc" && pwd != "123")
setTimeout(fooLoginError, 2000, "wrong pwd");
else if(uid == "abc" && pwd == "123")
setTimeout(fooLogined, 2000, uid);
}
private function fooLogined(uid:String):void{
this.dispatch(new ServiceLoginedEvent("USER_" + uid));
}
private function fooLoginError(errMsg:String):void{
this.dispatch(new ServiceLoginErrorEvent(errMsg));
}
}
}
Mediaotr,用來與 view component 溝通,接收感興趣的 "事件" 然後讓 view component 做出反應。
/idv/ben/view/AppMediator.as
package idv.ben.view
{
import idv.ben.event.MediatorLoginEvent;
import idv.ben.event.MediatorLogoutEvent;
import idv.ben.event.ModelEvent;
import idv.ben.event.ServiceLoginErrorEvent;
import idv.ben.event.ServiceLoginedEvent;
import idv.ben.event.ViewCompEvent;
import idv.ben.model.AppModel;
import mx.events.StateChangeEvent;
import mx.logging.Log;
import org.robotlegs.mvcs.Mediator;
public class AppMediator extends Mediator
{
[Inject]
public var viewComp:HelloRobotlegs;
[Inject]
public var appModel:AppModel;
override public function onRegister():void{
trace(this, "onRegister()");
this.addViewListener(ViewCompEvent.LOGIN_CLICKED, onLoginClicked);
this.addViewListener(ViewCompEvent.LOGOUT_CLICKED, onLogoutClicked);
this.addContextListener(ServiceLoginErrorEvent.SERVICE_LOGIN_ERROR, onServiceLoginError);
this.addContextListener(ModelEvent.LOGIN_STATUS_CHANGED, onModeLoginStatusChanged);
currentState = "login";
}
override public function onRemove():void{
trace(this, "onRemove()");
this.removeViewListener(ViewCompEvent.LOGIN_CLICKED, onLoginClicked);
this.removeViewListener(ViewCompEvent.LOGOUT_CLICKED, onLogoutClicked);
this.removeContextListener(ServiceLoginErrorEvent.SERVICE_LOGIN_ERROR, onServiceLoginError);
this.removeContextListener(ModelEvent.LOGIN_STATUS_CHANGED, onModeLoginStatusChanged);
}
private function set currentState(v:String):void{
viewComp.currentState = v;
if(v == "login"){
unluck();
viewComp.txtUID.text = "";
viewComp.txtPWD.text = "";
viewComp.txtErrorMessage.text = "";
}else if(v == "logon"){
viewComp.userName = appModel.userName;
}
}
private function onLoginClicked(e:ViewCompEvent):void{
trace(this, "onLoginClicked()");
luck();
var uid:String = viewComp.txtUID.text;
var pwd:String = viewComp.txtPWD.text;
this.dispatch(new MediatorLoginEvent(uid, pwd));
}
private function luck():void{
viewComp.txtUID.enabled = false;
viewComp.txtPWD.enabled = false;
viewComp.txtErrorMessage.text = "";
viewComp.btnSubmit.enabled = false;
}
private function unluck():void{
viewComp.txtUID.enabled = true;
viewComp.txtPWD.enabled = true;
viewComp.btnSubmit.enabled = true;
}
private function onLogoutClicked(e:ViewCompEvent):void{
trace(this, "onLogoutClicked()");
this.dispatch(new MediatorLogoutEvent());
currentState = "login";
}
private function onServiceLoginError(e:ServiceLoginErrorEvent):void{
trace(this, "onServiceLoginError()");
unluck();
viewComp.txtErrorMessage.text = e.errMsg;
}
private function onModeLoginStatusChanged(e:ModelEvent):void{
trace(this, "onModeLoginStatusChanged()");
if(appModel.loginStatus){
currentState = "logon";
}
}
}
}
接下來,準備了幾個 Command,可用來決定流程、決定收到的資料如何處理、通知下一個流程的開始......
/idv/ben/controller/LoginCommand.as
package idv.ben.controller
{
import idv.ben.service.AppService;
import idv.ben.event.MediatorLoginEvent;
import org.robotlegs.mvcs.Command;
public class LoginCommand extends Command
{
[Inject]
public var appService:AppService;
[Inject]
public var event:MediatorLoginEvent;
override public function execute():void{
trace(this, "execute()", "uid=" + event.uid, "pwd=" + event.pwd);
appService.login(event.uid, event.pwd);
}
}
}
/idv/ben/controller/LogoutCommand.as
package idv.ben.controller
{
import idv.ben.model.AppModel;
import org.robotlegs.mvcs.Command;
public class LogoutCommand extends Command
{
[Inject]
public var appModel:AppModel;
override public function execute():void{
trace(this, "execute()");
appModel.loginStatus = false;
appModel.userName = "";
}
}
}
/idv/ben/controller/LoginSuccessCommand.as
package idv.ben.controller
{
import idv.ben.event.ServiceLoginedEvent;
import idv.ben.model.AppModel;
import org.robotlegs.mvcs.Command;
public class LoginSuccessCommand extends Command
{
[Inject]
public var appModel:AppModel;
[Inject]
public var event:ServiceLoginedEvent;
override public function execute():void{
trace(this, "execute()");
appModel.userName = event.userName;
appModel.loginStatus = true;
}
}
}
剩下一些串通各角色之間的 VO (Value Object) 或 DTO (Data Transfer Object),以 Event 的形式存在,以下我將 source code 直接貼在一起:
package idv.ben.event
{
import flash.events.Event;
public class ViewCompEvent extends Event
{
static public const LOGIN_CLICKED:String = "loginClicked";
static public const LOGOUT_CLICKED:String = "logoutClicked";
public function ViewCompEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}
}
}
package idv.ben.event
{
import flash.events.Event;
public class MediatorLoginEvent extends Event
{
static public const LOGIN:String = "login";
public var uid:String;
public var pwd:String;
public function MediatorLoginEvent(uid:String, pwd:String)
{
super(LOGIN);
this.uid = uid;
this.pwd = pwd;
}
}
}
package idv.ben.event
{
import flash.events.Event;
public class MediatorLogoutEvent extends Event
{
static public const LOGOUT:String = "logout";
public function MediatorLogoutEvent()
{
super(LOGOUT);
}
}
}
package idv.ben.event
{
import flash.events.Event;
public class ServiceLoginErrorEvent extends Event
{
static public const SERVICE_LOGIN_ERROR:String = "serviceLoginError";
public var errMsg:String;
public function ServiceLoginErrorEvent(errMsg:String)
{
super(SERVICE_LOGIN_ERROR);
this.errMsg = errMsg;
}
}
}
package idv.ben.event
{
import flash.events.Event;
public class ServiceLoginedEvent extends Event
{
static public const SERVICE_LOGINED:String = "serviceLogined";
public var userName:String;
public function ServiceLoginedEvent(userName:String)
{
super(SERVICE_LOGINED);
this.userName = userName;
}
}
}
package idv.ben.event
{
import flash.events.Event;
public class ModelEvent extends Event
{
static public const LOGIN_STATUS_CHANGED:String = "loginStatusChanged";
public function ModelEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}
}
}
執行畫面:
沒輸入資料就送出:
輸入錯誤 UID:
輸入錯誤 PWD:
登錄成功:
以上過程的輸出訊息:
[SWF] E:\works_test\HelloRobotlegs\bin-debug\HelloRobotlegs.swf\[[DYNAMIC]]\1 - 370,463 bytes after decompression [SWF] E:\works_test\HelloRobotlegs\bin-debug\HelloRobotlegs.swf\[[DYNAMIC]]\2 - 650,777 bytes after decompression [SWF] E:\works_test\HelloRobotlegs\bin-debug\HelloRobotlegs.swf - 262,669 bytes after decompression [SWF] E:\works_test\HelloRobotlegs\bin-debug\HelloRobotlegs.swf\[[DYNAMIC]]\3 - 2,311,734 bytes after decompression [SWF] E:\works_test\HelloRobotlegs\bin-debug\HelloRobotlegs.swf\[[DYNAMIC]]\4 - 1,432,382 bytes after decompression [SWF] E:\works_test\HelloRobotlegs\bin-debug\HelloRobotlegs.swf\[[DYNAMIC]]\5 - 441,362 bytes after decompression [SWF] E:\works_test\HelloRobotlegs\bin-debug\HelloRobotlegs.swf\[[DYNAMIC]]\6 - 323,354 bytes after decompression [object AppContext] AppContext() contextView=null [object AppContext] startup() [object AppMediator] onRegister() [object AppMediator] onLoginClicked() [object LoginCommand] execute() uid= pwd= [object AppMediator] onServiceLoginError() [object AppMediator] onLoginClicked() [object LoginCommand] execute() uid=aaa pwd=fff [object AppMediator] onServiceLoginError() [object AppMediator] onLoginClicked() [object LoginCommand] execute() uid=abc pwd=fff [object AppMediator] onServiceLoginError() [object AppMediator] onLoginClicked() [object LoginCommand] execute() uid=abc pwd=123 [object LoginSuccessCommand] execute() [object AppMediator] onModeLoginStatusChanged() [object AppMediator] onLogoutClicked() [object LogoutCommand] execute() [object AppMediator] onModeLoginStatusChanged()




0 意見:
張貼意見