项目地址:https://github.com/boycy815/asroutehtml
首先明确几个概念git
状态:github
不少状况下,一个复杂的UI组件可能会有不少种不一样的“状态”,不一样的“状态”下组件自己对外界会有不一样的行为,外界根据组件的“状态”会对其作不一样的操做。网络
状态节点:函数
组件的“状态”状况由一系列“状态节点”共同决定,每一个“状态节点”都是一个只有两种值的布尔值。通常“状态节点”都会有必定意义,好比“在家”,“在公司”这是两个地理位置维度上的“状态节点”。若是“在家”这个“状态节点”被选中(值为true),那么表示当前正在家里。测试
子状态:ui
某个“状态节点”可能有更详细的描述,举个例子说明,若是“在家”算做一种“状态节点”,那么“在客厅”和“在厨房”应该算做“在家”的“子状态”。“子状态”被选中时,其父节点必定会先被选中。spa
互斥状态:code
“互斥状态”也是个“状态节点”,他的“子状态”不能同时被选中,一般状况下这些“子状态”都是对同一个维度的事实进行描述,好比“在客厅”和“在家”都是在地理位置进行描述,一我的不可能同时在客厅和在厨房吧。视频
共存状态:
“共存状态”也是个“状态节点”,他的“子状态”容许同时被选中,一般他的“子状态”描述的都是不一样维度的事实,好比“在客厅”和“睡觉”。
咱们把上面介绍的几种状态节点组成树形状态,就能很好的描述当前系统处于什么样的状态。下面咱们经过视频播放器举例说明
咱们须要播放器有“close”,“inited”,“streaming”三种状态节点,其中close表示播放器未载入任何播放信息,inited表示已经载入播放信息随时能够准备开始播放,streaming表示已经链接,三种状态不能同时存在,因此是互斥的。
其中streaming状态带有“playing”和“buffering”两个子状态,分别从两个维度描述当前播放状况,属于共存状态。playing有play和pause是两个互斥状态,表示用户当前将播放器暂停或者播放;buffering有full和empty两个互斥状态,表示当前网络加载状况引发的状态。
这样的结构很好的描述了播放器的状态和各个状态节点之间的制约关系。下面咱们经过asroute用代码把它描述出来。
var player:OrState = new OrState(); var close:State = new State(player); var inited:State = new State(player); var streaming:State = new State(player); var playing:OrState = new OrState(streaming); var play:State = new State(playing); var pause:State = new State(playing); var buffering:OrState = new OrState(streaming); var full:State = new State(buffering); var empty:State = new State(buffering);
OrState和State的构造函数参数为状态节点的父节点,一旦指定父级(或者不指定)就不能更改;OrState为State的子类,其子状态是互斥状态。
当某个状态被选中后发生事件的顺序:
当一个状态节点从未选中转变成选中时(值从false变为true),会发生StateEventConst.ENTER事件,从选中转变成未选中时(值从false变为true),会发生StateEventConst.EXIT事件。
若是一个状态节点在被选中的时候,其父级一定被选中。因此为了维持这个关系,若是一个状态节点即将被选中而其父级没有被选中,那么系统会自动先将其父级选中,这个规则会一直对其爷爷级祖宗级生效。另外若是对一个状态节点取消选中,那么在此以前其全部子状态也会先被取消选中。
OrState的特殊性在于,当其子状态被选中时,其余已被选中的子状态会先被取消选中。
能够经过下面的代码监听状态的改变
player.addEventListener(StateEventConst.ENTER, function(e:Event):void { trace("player enter") } ); player.addEventListener(StateEventConst.EXIT, function(e:Event):void { trace("player exit") } ); close.addEventListener(StateEventConst.ENTER, function(e:Event):void { trace("close enter") } ); close.addEventListener(StateEventConst.EXIT, function(e:Event):void { trace("close exit") } ); inited.addEventListener(StateEventConst.ENTER, function(e:Event):void { trace("inited enter") } ); inited.addEventListener(StateEventConst.EXIT, function(e:Event):void { trace("inited exit") } ); streaming.addEventListener(StateEventConst.ENTER, function(e:Event):void { trace("streaming enter") } ); streaming.addEventListener(StateEventConst.EXIT, function(e:Event):void { trace("streaming exit") } ); playing.addEventListener(StateEventConst.ENTER, function(e:Event):void { trace("playing enter") } ); playing.addEventListener(StateEventConst.EXIT, function(e:Event):void { trace("playing exit") } ); play.addEventListener(StateEventConst.ENTER, function(e:Event):void { trace("play enter") } ); play.addEventListener(StateEventConst.EXIT, function(e:Event):void { trace("play exit") } ); pause.addEventListener(StateEventConst.ENTER, function(e:Event):void { trace("pause enter") } ); pause.addEventListener(StateEventConst.EXIT, function(e:Event):void { trace("pause exit") } ); buffering.addEventListener(StateEventConst.ENTER, function(e:Event):void { trace("buffering enter") } ); buffering.addEventListener(StateEventConst.EXIT, function(e:Event):void { trace("buffering exit") } ); full.addEventListener(StateEventConst.ENTER, function(e:Event):void { trace("full enter") } ); full.addEventListener(StateEventConst.EXIT, function(e:Event):void { trace("full exit") } ); empty.addEventListener(StateEventConst.ENTER, function(e:Event):void { trace("empty enter") } );
控制状态节点改变:
每一个状态节点都有个select方法,因此咱们能够随意得选中咱们想要的状态节点,系统会自动处理每一个状态节点的关系,如
var ui:TextField = new TextField(); addChild(ui); ui.width = 800; ui.height = 600; ui.htmlText = '<a href="event:player">player</a>\n<a href="event:close">close</a>\n<a href="event:inited">inited</a>\n<a href="event:streaming">streaming</a>\n<a href="event:playing">playing</a>\n<a href="event:play">play</a>\n<a href="event:pause">pause</a>\n<a href="event:buffering">buffering</a>\n<a href="event:full">full</a>\n<a href="event:empty">empty</a>\n'; ui.addEventListener(TextEvent.LINK, onLink); function onLink(e:TextEvent):void { if (e.text == "player") { player.select(); } if (e.text == "close") { close.select(); } if (e.text == "inited") { inited.select(); } if (e.text == "streaming") { streaming.select(); } if (e.text == "playing") { playing.select(); } if (e.text == "play") { play.select(); } if (e.text == "pause") { pause.select(); } if (e.text == "buffering") { buffering.select(); } if (e.text == "full") { full.select(); } if (e.text == "empty") { empty.select(); } } //自定义状态机跳转测试 inited.addEventListener(StateEventConst.ENTER, function(e:Event):void { close.select() } ); streaming.addEventListener(StateEventConst.ENTER, function(e:Event):void { close.select() } ); play.addEventListener(StateEventConst.EXIT, function(e:Event):void { play.select() } );
可是有一点是要注意的,你不能直接让一个状态节点的值置为false,由于状态节点的值被置为false必定是由于别的互斥状态被选中而引发的。