何时在ZK生命周期中编写组件?

3

问题:
在ZK中,当使用自定义组件时,生命周期中什么时候构建组件内容最好(任意复杂度)。也就是说,在什么时候可以安全地假设我们已经从视图获取了所有数据,但是不需要等待太久。

详细信息:
在ZK中,我可以创建一个自定义组件MyCoolComponent

package my.package;

public class MyCoolComponent extends Div {

  private String title;

  public MyCoolComponent() {
    Selectors.wireVariables(this, this, Div.class);
    Selectors.wireComponents(this, this, false);
    Selectors.wireEventListeners(this, this);
  }

  public String getTitle() {
    return title;
  }

  public void setTitle(String title) {
    this.title = title;
  }

  // When is the correct time to call this function?
  public void initializeComponent() {
    appendChild(new Label(title));
    // arbitrarily complex initialization follows ..
  }

}

我可以像这样在zul文件中使用自定义组件:

我可以在 zul 文件中使用我的自定义组件,方法如下:

<?component name="coolcomponent" class="my.package.MyCoolComponent" ?>
<zk>
  <coolcomponent id="cool" height="200px" title="Sean is Cool" />
</zk>

现在,当使用这个 Component 时,我想添加子 Components,例如,通过在 MyCoolComponent 中调用 initializeComponent 函数。

Composers 的世界中,我们被教导要在生命周期的 After Compose 阶段中处理所有这类工作,使用 doAfterCompose 函数。如果像这样创建了一个 Component,是否也是如此呢?如果是,最佳(即高效、安全、易读)的方法是什么?我觉得为 onRender 事件附加 @Listen 是不太好的方式。有什么建议吗?

2个回答

1
据我所了解zk文档,构造函数类似于doAfterCompose,如果您像示例中那样调用Selectors方法。
但是您想要做的可能是:
public void setTitle(String title) {
  this.title = title;
    if(label != null)
      appendChild(new Label(title));
    else
      lebel.setValue(title);
}

zk的生命周期是这样的,当进入一个zul组件<MyComponent>时,它会调用构造函数,如果有像title="Sean is Cool"这样的东西,它会调用设置方法,如果对所有Components都完成了这个过程,它就创建了页面。
这对你有帮助吗?

编辑

对于更复杂的结构,有两个选项

  1. 创建一个具有所需结构的zul文件,并使用Executions#CreateComponent
  2. 创建自己的zk-Component-Widget

哪一个是适合您目的的正确选择?

  • 如果您有一个zk组件的结构想要(重新)使用,选择1。
    一个论坛帖子的结构可能就是这样的。
  • 如果您想要添加特殊功能、优化/定制客户端-服务器通信、编写JavaScript库的绑定、在客户端保持内存大小小(即使对于复杂结构,您只需要一个类)等,请选择2。
    拥有自己的组件肯定有很多好处,但实现它们需要时间。

那么生命周期怎么办呢?对于选项2,只需阅读文档即可。
对于选项1,在doAfterCompose或事件监听器/处理程序中执行。

好的,这里有一个选项1的示例。

主zul文件

<zk>
  ...
  <div id="menu" use="myPkg.MyMenu" item1="omg" />
  ...
</zk>

我的菜单定义

<vbox>
  <label id="item1" value="${arg.item1}">
  ...
</vbox>

Java

class MyMenu extends Div {
  String item1;
  ...
  public void setItem1(String x){
    item1 = x;
  }

  // onCreate is fired before data is send to the client,
  // but after the Component and all it children exists.
  public void onCreate(CreateEvent ev){
    Executions.CreateComponents("MenuDef.zul", this, new HashMap<String, Object>(){{
        put("item1", item1);
    }});
  }
}

您可以在主要的zul文件中的doAfterCompose中调用Executions.CreateComponents,但是如果您想要在zul中设置值,那么使用onCreate的方式更好。
onCreate()中通过Java添加组件也可以正常工作,但是如果您将这些内容写在zul中,它会更易读/易于维护。

现在来回答您的问题:
最好的时间是在doAfterCompose中初始化您的Components,并监听Create Event


做了一些编辑,可能会对你有所帮助。如果不行,你有什么问题或者认为可能存在什么问题? - Nabil A.
嗯,我非常反对重载setter方法。当有人在API中看到setTitle时,惯例表明他们可以假设它只做那一件事情。从setTitle函数影响DOM将是一个对我来说很糟糕的设计选择。 - Sean Connolly
请记住,这是一个“视图”类,如果您在视图中设置了某些内容,则必须更新所显示的内容。那么你想做什么?你认为zk在其“组件”中正在做什么?请查看zk类的内部。 - Nabil A.
我理解,但我认为这是一条非常微妙的界限。在这个例子中,我会说这种方法可能是可以接受的。但在一个更复杂的组件中,有许多需要构建的部分,一次在一个位置完成会更加清晰。考虑不仅仅是带标签的Div,还有导航栏、或者是步骤向导窗口等等。我真的很想知道初始化这些复杂自定义组件的最佳位置和时间。 - Sean Connolly
问题不在于如何组织代码,而是如题所述,何时组合组件。我已经选择了您提出的第一个选项。现在的问题是何时组合组件。采用这种方法时,没有与ZK生命周期绑定的“doAfterCompose”函数。 - Sean Connolly
显示剩余2条评论

0
在ZK中,子节点将在其父节点之前创建,您可以在子节点的onCreate事件触发时设置值,或者在MyCoolDiv的构造函数中添加监听onCreate事件的事件侦听器,然后在该侦听器中调用init。
有关更多信息,请参阅zk fiddle上的示例Div test

我简化了示例以强调我想要做的事情。将标签添加到Div不是我的问题。我的问题是关于初始化自定义组件/小部件的内容的最佳实践,无论它们的内容是标签还是其他东西。在生命周期中什么时候是最佳时间点,如何有效地利用它? - Sean Connolly
在您更新的情况下,我认为您可以在构造函数完成后立即调用init方法。 - benbai123
不,此时还没有调用setTitle..这就是我的问题。我提供的代码是一个SSCCE,如果你测试这段代码,你会发现你的解决方案会得到一个NPE。 - Sean Connolly
抱歉,可能有些误解了你的问题,请查看更新后(已更正)的答案。 - benbai123

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接