JSF 最佳实践:自定义组件和 JavaScript

Posted

技术标签:

【中文标题】JSF 最佳实践:自定义组件和 JavaScript【英文标题】:JSF Best Practice: Custom Components and JavaScript 【发布时间】:2014-08-22 00:58:46 【问题描述】:

我正在开发一个 JSF 自定义组件,使用我在以下书籍 Pro JSF and html5 by Apress 中找到的信息。

到目前为止,我成功开发了:

获取要在组件中渲染的数据的java类 java 组件类 java 渲染器类 标签库文件 呈现标签库的示例页面

一切正常,组件渲染成功。

现在我想为渲染的元素添加javascript事件和行为,更具体地说,我的自定义组件的目的是在网页上渲染一个菜单,我想广告菜单项的下拉效果。我知道如何用 JavaScript 编写整个代码,但我不知道的是:

向自定义组件中呈现的元素添加 javascript 事件和行为的最佳做法是什么?

JS文件应该放在哪里?如何将事件绑定到元素?是在渲染类中完成,还是在网页上完成?

谢谢,如果需要,我愿意提供有关我的代码的更具体信息。


Java 组件类

注意: CosmoMenu 类只是一个 bean。它基本上存储了一个菜单树(一个标签、一个 id 和一组子项,如果有的话)。

package components;

import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import domain.CosmoMenu;
import javax.faces.component.FacesComponent;
import javax.faces.component.UIComponentBase;


@FacesComponent(CosmoMenuComponent.COMPONENT_TYPE)
public class CosmoMenuComponent extends UIComponentBase

  /** Component family of @link CosmoMenuComponent.        */
  public static final String COMPONENT_FAMILY = "CosmoMenu";

  /** Component type of @link CosmoMenuComponent.          */ 
  public static final String COMPONENT_TYPE = "CosmoMenu";    

  @Override
  public String getFamily()
      return CosmoMenuComponent.COMPONENT_FAMILY;
  


  private CosmoMenu theMenu;    

  public CosmoMenu getMenu()

      Gson gson = new Gson();
      JsonParser jsonParser = new JsonParser();
      CosmoMenuAPI myApi = new CosmoMenuAPI();

      String strMenu = myApi.getMenu();
      JsonElement jEl = jsonParser.parse(strMenu);

      theMenu = gson.fromJson(jEl, CosmoMenu.class);
      return theMenu;      
  

【问题讨论】:

你能发布你的组件吗? :) 只需要了解如何生成示例。 如果您也需要渲染器或其他任何东西,请告诉我。 【参考方案1】:

如果您希望您的组件可重复使用,我鼓励您将所有内容打包在一个独立的 jar 中。如果使用 Servlet 3.0,您将能够轻松访问将它们放在 META-INF/resources 中的 Web 资源。为 jar 提供一个 faces-config.xml,您将使其 JSF 注释可扫描:

components
    \-(Your cource code)
META-INF 
    \-faces-config.xml
    \-resources (This ends up in docroot)
        \-resources
            \-js (Here they go your js files)
            \-comp (Here your composite components)
            \-css (Here your css)

稍后,您将不得不注意避免复合中的特定 ID,因为 JSF 在渲染时会修改它们。您最好将当前组件引用传递给您的 JS 函数:

<h:inputText styleClass="myInputStyle" onclick="showInputText(this)" />

只需参考包含的 CSS 样式和 JS 函数即可。

最后但同样重要的是,在将 jar 包含为 Web 资源时要小心,如果文件路径与您的 Web 应用程序中的文件路径仍然冲突,它们将不会被包含在内。

另请参阅:

Exposing resources from jar files in web applications (Tomcat7) How to reference JSF managed beans which are provided in a JAR file? How can I know the id of a JSF component so I can use in Javascript

【讨论】:

@Biker 我正在使用自定义组件,而不是复合组件,我认为我不应该创建“comp”目录,对吧?关于 JS 事件:HTML 的呈现由 java 类执行,而不是由 xhtml 页面(如在复合组件中)执行,将 JS 事件附加到 java 渲染器类中的元素是否常见(或做得很好) ,由 JS 文件中的函数处理? @INElutTabile,这个布局让你决定如何实现你的组件。复合组件只需为其声明添加一个 xhtml 视图层,因此如果您只想使用 java 代码,您可以,因为复合组件可以实现的所有功能也可以使用自定义组件完成。我推断您正在使用该框架,因为使用自定义组件来实现这种行为对我来说太过分了,而且当 JSF 2.x 可用时。这里有一些相关链接:bit.ly/1lP5mKsbit.ly/VCPIIx @Biker 感谢您的帮助!如果可以的话,我希望您在答案中添加另一个重要的(恕我直言)细节。我知道我需要的每个 JS 资源都必须包含在我的页面中,才能使用。我正在使用 Java 渲染器类,我想我必须在此类中包含 js 资源才能使用它。正确的?在渲染器类中执行写入是否正确,包括我的 js 资源,例如 'responseWriter.write(" @INElutTabile 不客气 ;-) 我对自定义渲染器的经验很少,基本上我从来没有自己实现过。但是,是的,我认为您使用responseWriter 的方式是正确的。关于您与动态菜单相关的声明,无需使用自定义渲染器+ no-facelets。那是矫枉过正。与复合材料一起使用,它们也可以由自定义组件支持,并且可能具有关联的 facelet(视图)。您可以实现您想要的,只需在组件中为您的菜单设置一个结构,并在您的视图中使用 ui:repeat 对其进行迭代。 顺便说一句,你想做的已经been implemented了。你是否想DIY是另一回事;-)【参考方案2】:

您可以通过添加以下代码在使用您的组件的 facelets 中包含一个外部 javascript 文件:

    <script src="#request.contextPath/jspath/yourjs.js"></script>

当您生成 XHTML 输出时,在组件内为您的菜单条目提供一个 Id,例如

    <h:outputText id="myid" value="#bean.value"/>

在你的js.js中

    $(document).ready(function() 

    $("#myid").click(function()
    // dostuff
    );
    );

【讨论】:

以上是关于JSF 最佳实践:自定义组件和 JavaScript的主要内容,如果未能解决你的问题,请参考以下文章

JSF 生命周期和自定义组件

关于 JSF 2.0 自定义组件和 Primefaces 的帮助

JSF 自定义复合组件与自定义经典组件有啥区别

JSF 为组件声明定义自定义命名空间

Vue最佳实践和实用技巧

jsf 2.0 自定义组件/标签不复合