我正在构建一个复杂的Flex应用程序,现在我处于导航成为问题的地步。我使用带有菜单栏的Viewstacks,但我不确定如何清楚地构建它。
根据用户登录的用户和所选公司,他可以看到不同的页面。现在我限制了这个隐藏菜单栏中的相应按钮。但是,不仅菜单栏,而且应用程序内的按钮/链接应该能够导航到每个现有页面。
当我加载现有页面时,它需要一些初始化(取决于它从中加载的上下文)。此外,当选择公司时,我需要从后端加载状态,并根据此状态显示特定页面。
是否有任何指导如何在Flex中处理更复杂的导航/网站层次结构?
现在我在Application中的视图堆栈中拥有所有视图,并使用Application.application.appViews.selectedChild - >来引用它。但这显然不是最佳做法,因为它违反了封装。
正在考虑实施某种状态机,它负责所有这些,但不太确定这是否有意义,或者是否有更好的方法。
谢谢你们, 马丁
答案 0 :(得分:1)
如果它非常复杂,您可能需要考虑将应用程序分解为模块。
此外,Mate是一个出色的Flex框架,用于处理复杂的通信和导航。 Mate的EventMaps可以帮助您集中组件,模块等之间的通信和逻辑。并且,它可以让您远离可怕的Application.application引用。
即使您不使用Mate这样的框架,也可以通过让组件调度自定义事件来避开Application.application引用,这些自定义事件会冒泡到应用程序的顶层。应用程序的顶层可以监听并捕获这些事件并对其进行操作。我发现这是一种更灵活的方法。我尽可能避免使用Application.application!
如果你有一个复杂的菜单栏需要根据许多不同的逻辑条件启用/禁用很多按钮或选项,那么状态模式是处理它的一种不错的方法。我构建了一个企业级应用程序,顶部有一个“类似Word”的按钮栏......有很多不同的条件会影响按钮的状态,我必须将逻辑集中在一个地方。起初我没有使用State模式,维护代码是一件困难的事。有一天,我咬紧牙关并将所有条件逻辑重新计算到StateManager类中。从那以后,它确实让生活更轻松。
答案 1 :(得分:0)
同样,您可能需要考虑使用自定义事件向您的应用程序广播重要事件。您可以将这些事件冒泡到应用程序级别。然后,通过在应用程序级别添加事件侦听器,您可以从应用程序级别捕获并响应这些事件和目标组件或模块。这为您提供了处理事件和“引导流量”的中心位置。它还可以防止Application.application方法的紧耦合。 (随着应用程序的增长和扩展,这很快就变成了一场噩梦!)
例如,您的StateManager可以包含case语句,用于决定应用程序需要处于哪种状态。一旦确定了有关当前状态的决定,您将调度自定义StateEvent。 (可能具有StateEvent.STATE_CHANGED和StateEvent.CURRRENT_STATE等属性)此事件可以冒泡到应用程序级别并被侦听器捕获。然后,侦听器调用一个方法来加载/更改状态。
这是否为您澄清?如果没有,也许我可以花一两个小时把一些样品放在一起。
让我知道,
=布赖恩=
答案 2 :(得分:0)
我可以为您提供我用于某些子问题的方法,在运行时初始化页面的问题以及如何封装导航。
对于页面初始化,我遇到的问题是,一旦导航到页面,是否应显示某些元素并不总是知道,因为它不仅取决于整体用户权限,还取决于当前所选的权限数据。如果必须从服务器加载确定此信息所需的信息,则在加载信息时无法按原样显示页面。因此,我们创建了一个名为LoadingPanel的控件,它是一个容器,可以覆盖带有加载指示符的内容,直到收到其他信息。这是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并将用户“发送”到适当的区域。
希望这能为您提供一些面对挑战的想法。