在Flex中处理复杂的导航
我正在构建一个复杂的Flex应用程序,现在我处于导航成为问题的地步。我使用Viewstack与菜单栏,但我不知道如何清晰地构造这个。在Flex中处理复杂的导航
根据登录的用户和用户选择的公司,他可以看到不同的页面。现在我限制了它隐藏菜单栏中的相应按钮。但是,不仅仅是菜单栏,而且应用程序中的按钮/链接都应该能够导航到每个现有页面。
当我加载一个现有的页面时,它需要一些初始化(取决于从它加载的上下文)。另外,选择公司时,我需要从后端加载状态,并且根据此状态,可能会显示特定的页面。
是否有任何指导方针如何解决Flex中更复杂的导航/网站层次结构?
现在,我在应用程序的viewstack中拥有所有视图,并将其与Application.application.appViews.selectedChild - >引用,但这显然不是最佳实践,因为它违反了封装。
正在考虑实施某种状态机,它负责处理所有这些事情,但不太清楚这是否合理,或者是否有更好的方法。
谢谢你们, 马丁
如果它真的复杂,你可能要考虑将您的应用程序成模块。
此外,Mate是一个伟大的Flex框架,用于处理复杂的通信和导航。 Mate的EventMaps可以帮助您集中组件,模块等之间的通信和逻辑。并且,它使您远离可怕的Application.application引用。
即使您不使用像Mate这样的框架,也可以通过让组件调度自定义事件,使其引发到应用程序的顶层,从而避免引用Application.application。应用程序的顶层可以监听并捕获这些事件并对其执行操作。我发现这是一个更灵活的方法。尽可能避免Application.application!
如果你有一个复杂的菜单栏需要启用/禁用很多不同的逻辑条件的按钮或选项,状态模式是一个体面的方式来处理它。我构建了一个企业级应用程序,在顶部有一个“类似于Word的”按钮栏......并且有太多不同的条件影响了按钮的状态,我必须将逻辑集中在一个位置。起初我没有使用国家模式,维护代码是一件困难的事情。有一天,我咬紧牙关,重新将所有的条件逻辑分解成一个StateManager类。从那里开始,它绝对让生活更轻松。
同样,您可能需要考虑使用自定义事件向应用程序广播重要事件。您可以使这些事件起泡到应用程序级别。然后,通过在应用程序级别添加事件侦听器,您可以捕获并响应这些事件并从应用程序级别定位组件或模块。这为您提供处理事件和“指挥交通”的中心位置。它还可以防止Application.application方法的紧密结合。 (随着应用程序的增长和扩展,这很快就会变成一场噩梦!)
例如,您的StateManager可以包含用于决定您的应用程序需要处于哪种状态的case语句。一旦确定了有关当前状态的决定,会派遣一个自定义的StateEvent。(它可能具有像StateEvent.STATE_CHANGED和StateEvent.CURRRENT_STATE这样的属性)此事件可以冒泡到应用程序级别并被侦听器捕获。侦听器然后调用加载/更改状态的方法。
这是否为您澄清?如果没有,也许我可以花一两个小时放一些样品。
让我知道,
=布莱恩=
我可以给你我用你的一些小问题的方法,在运行时初始化页面,如何封装导航的问题。
对于页面初始化,我遇到的问题是,一旦您导航到页面时,并不总是知道是否应该显示某些元素,因为它不仅取决于整体用户权限,还取决于当前用户的权限,选定的数据。如果需要确定这些信息必须从服务器加载,则在加载信息时无法显示该页面。所以我们创建了一个名为LoadPanel的控件,它是一个容器,它可以用一个加载指示符覆盖内容,直到收到其他信息。下面是ActionScript中的一个缩短的版本:
[DefaultProperty("children")]
public class LoadingPanel extends ViewStack
{
public function LoadingPanel()
{
this.resizeToContent = false;
super();
}
public function get children():Array { return _children }
public function set children(value:Array):void { _children = value; }
public function get loadingImageStyle():String {
return _loadingImgStyle; }
public function set loadingImageStyle(value:String):void {
_loadingImgStyle = value;
if (_loadingIndic)
_loadingIndic.loadingImageStyle = value;
}
public function showLoadingIndicator():void
{
if (_loadingIndic)
{
super.selectedChild = _loadingIndic;
}
else
{
_pendingLoadingIndic = true;
var me:LoadingPanel = this;
var listener:Function = function(event:Event):void
{
if (me._pendingLoadingIndic)
me.showLoadingIndicator();
}
addEventListener(FlexEvent.CREATION_COMPLETE, listener);
}
}
public function hideLoadingIndicator():void
{
_pendingLoadingIndic = false;
if (_content)
{
super.selectedChild = _content;
}
else
{
var me:LoadingPanel = this;
var listener:Function = function(event:Event):void
{
me.hideLoadingIndicator();
}
addEventListener(FlexEvent.CREATION_COMPLETE, listener);
}
}
public function waitForEvent(target:EventDispatcher, event:String):void
{
_eventCount++;
showLoadingIndicator();
var me:LoadingPanel = this;
target.addEventListener(
event,
function(evt:Event):void
{
me._eventCount--;
if (!me._eventCount)
{
me.hideLoadingIndicator();
}
}
);
}
override public function addChild(child:DisplayObject):DisplayObject
{
var result:DisplayObject = child;
if (_content)
{
result = _content.addChild(child);
invalidateDisplayList();
}
else
{
if (!_children)
{
_children = [];
}
_children.push(child);
}
return result;
}
override protected function createChildren():void
{
super.createChildren();
if (!_content)
{
_content = new Box();
_content.percentWidth = 1.0;
_content.percentHeight = 1.0;
super.addChild(_content);
}
if (!_loadingIndic)
{
_loadingIndic = new LoadingIndicator();
_loadingIndic.percentWidth = 1.0;
_loadingIndic.percentHeight = 1.0;
_loadingIndic.loadingImageStyle = _loadingImgStyle;
super.addChild(_loadingIndic);
}
if (_children)
{
for each (var child:DisplayObject in _children)
{
_content.addChild(child);
}
}
}
private var _loadingImgStyle:String = "loadingIndicatorDark";
private var _loadingIndic:LoadingIndicator = null;
private var _content:Box = null;
private var _children:Array = null;
private var _pendingLoadingIndic:Boolean = false;
private var _eventCount:int = 0;
}
我们通常会通过包装一个LoadingPanel
围绕内容然后调用面板的waitForEvent
方法使用这些。通常情况下,我们要等待的事件是为了提供Web服务响应。该类还允许您在多个事件显示其子级之前等待多个事件。
我会为您的项目提出的另一个建议是,您将看到Flex中的深层链接。我们的用户赞赏能够在复杂的Flex应用程序中为资源/位置添加书签,并且能够在浏览器中进行刷新并返回到他们所在的相同“页面”。但是实施深度链接也帮助我解决了你提到的其中一个问题。你如何以封装的方式将UI发送到特定页面?我们这样做的方式是通过引发包含目标“URL”的冒泡导航事件。顶级导航“经理”然后处理解释URL并将用户“发送”到适当的区域。
希望这会给你一些你面临的挑战的想法。
嗨布赖恩, 谢谢你的答案。伴侣听起来有趣 - 对于这个项目,尽管我可能会坚持国家模式。然而,你是如何设法摆脱状态管理器中的Application.application引用的(我创建了一个Singleton类)? 我的菜单和我的ViewStack位于应用程序文件中,状态管理器经常引用它们。 谢谢, Martin – martin 2010-02-05 08:55:42