如何为 JSF 自定义组件动态生成 CSS
Posted
技术标签:
【中文标题】如何为 JSF 自定义组件动态生成 CSS【英文标题】:How can I dynamically generate a CSS for a JSF custom component 【发布时间】:2013-12-18 00:23:53 【问题描述】:我正在开发一个执行“响应式”多列显示的 JSF 自定义组件。
它使用“CSS 多列布局模块”(http://www.w3.org/TR/css3-multicol/)(法语教程:http://www.alsacreations.com/tuto/lire/1557-les-multicolonnes-en-css3.html)。
我实际上有以下解决方案,它有效:
组件类:
@Log4j
@FacesComponent(ResponsiveMultiColumnsTable.SENAT_COMPONENT_TYPE)
@ResourceDependency(library="senat",name="senat-columns.css")
public class ResponsiveMultiColumnsTable extends UIData
public static final String SENAT_COMPONENT_FAMILY = "fr.senat.faces.components";
public static final String SENAT_COMPONENT_TYPE = SENAT_COMPONENT_FAMILY + ".ResponsiveMultiColumnsTable";
public static final String DEFAULT_RENDERER = SENAT_COMPONENT_FAMILY + ".ResponsiveMultiColumnsPanelRenderer";
private enum PropertyKeys style, styleClass
public ResponsiveMultiColumnsTable()
setRendererType(DEFAULT_RENDERER);
@Override
public boolean getRendersChildren()
return true;
public String getStyle()
return (String) getStateHelper().eval(PropertyKeys.style);
public void setStyle(String param)
getStateHelper().put(PropertyKeys.style, param);
public String getStyleClass()
return (String) getStateHelper().eval(PropertyKeys.styleClass);
public void setStyleClass(String param)
getStateHelper().put(PropertyKeys.styleClass, param);
渲染器类:
@FacesRenderer(componentFamily = ResponsiveMultiColumnsTable.COMPONENT_FAMILY, rendererType = ResponsiveMultiColumnsTable.DEFAULT_RENDERER)
public class ResponsiveMultiColumnsTableRenderer extends CoreRenderer
@Override
public void encodeBegin(FacesContext context, UIComponent component) throws IOException
ResponsiveMultiColumnsTable detail = (ResponsiveMultiColumnsTable) component;
ResponseWriter writer = context.getResponseWriter();
String clientId = detail.getClientId(context);
String style = detail.getStyle();
String styleClass = detail.getStyleClass();
writer.startElement("div", detail);
writer.writeAttribute("id", clientId, "id");
String extStyleClass = "senat-details-columns";
if (styleClass != null)
extStyleClass += " " + styleClass;
writer.writeAttribute("class", "senat-details-columns " + extStyleClass, "styleClass");
if ((style != null) && !style.isEmpty())
writer.writeAttribute("style", style, "style");
@Override
public void encodeEnd(FacesContext context, UIComponent component) throws IOException
ResponseWriter writer = context.getResponseWriter();
writer.endElement("div");
@Override
public void encodeChildren(FacesContext context, UIComponent component) throws IOException
ResponseWriter writer = context.getResponseWriter();
ResponsiveMultiColumnsTable grid = (ResponsiveMultiColumnsTable) component;
int rowIndex = grid.getFirst();
int rows = grid.getRows();
int itemsToRender = rows != 0 ? rows : grid.getRowCount();
for(int i = rowIndex ; i < itemsToRender ; i++)
grid.setRowIndex(i);
if(!grid.isRowAvailable())
break;
writer.startElement("div", null);
renderChildren(context, grid);
writer.endElement("div");
taglib 中的组件声明:
<tag>
<description>
<![CDATA[
*** À compléter ***
]]>
</description>
<tag-name>responsiveMultiColumnsTable</tag-name>
<component>
<component-type>fr.senat.faces.components.ResponsiveMultiColumnsTable</component-type>
</component>
<attribute>
<description>Liste à afficher
</description>
<name>value</name>
<required>true</required>
<type>java.util.List</type>
</attribute>
<attribute>
<description>Nom de la variable d'itération</description>
<name>var</name>
<required>true</required>
<type>java.lang.String</type>
</attribute>
<attribute>
<description>Élément de style à ajouter</description>
<name>style</name>
<required>false</required>
<type>java.lang.String</type>
</attribute>
<attribute>
<description>Classe à ajouter</description>
<name>styleClass</name>
<required>false</required>
<type>java.lang.String</type>
</attribute>
</tag>
样式表:
.senat-details-columns
-webkit-columns: 3;
-moz-columns: 3;
columns: 3;
@media (max-width: 1024px)
.senat-details-columns
-webkit-columns: 2;
-moz-columns: 2;
columns: 2;
@media (max-width: 640px)
.senat-details-columns
-webkit-columns: 1;
-moz-columns: 1;
columns: 1;
我希望能够指示数据,例如在哪种分辨率下使用哪个列数。一种方法是动态生成样式表片段,然后包含它。
基本动态样式表如下所示:
.#dynamic-style
-webkit-columns: #max-col-count;
-moz-columns: #max-col-count;
columns: #max-col-count;
@media (max-width: #max-middle-respx)
.#dynamic-style
-webkit-columns: #middle-col-count;
-moz-columns: #middle-col-count;
columns: #middle-col-count;
@media (max-width: #max-min-respx)
.#dynamic-style
-webkit-columns: #min-col-count;
-moz-columns: #middle-col-count;
columns: #middle-col-count;
如何动态处理并包含它?
我看到的问题是我可以多次使用具有不同参数的同一个样式表。如果只有一种用途,只需在样式表中包含 EL 表达式即可。
另一种解决方案是在组件之前添加样式,但这对我来说有点难看。
【问题讨论】:
JSF 是一个在服务器端动态生成客户端代码的工具。考虑到该分辨率是特定于客户端的,因此很难在服务器端使用它。我认为你能做到的最好的就是在客户端设备本身之间有所不同(考虑一些框架,比如Spring Mobile)。 @XtremeBiker 或使用已经简化这项工作的前端框架,例如Bootstrap 这些变量应该是基于请求的还是会话范围的或应用程序范围的?您打算在哪里/如何准备/设置这些 EL 变量? @BalusC 我会将它们作为自定义组件的参数传递。类似于您可以简单地将 EL 表达式放入 .ccs 文件中,JSF 将像处理 .xhtml 文件一样处理它们。
您需要将它们包含在 <h:outputStylesheet
中或直接从 HTML 中使用 /javax.faces.resource/foo.css?ln=bar
。
【讨论】:
如果数据是基于请求的,那将不起作用。显然,CSS 文件是在与具有特定组件的 JSF 页面完全不同的 HTTP 请求中请求的。当我在问题的 cmets 中询问时,OP 并不清楚这一点,因此不可能给出有效的答案。以上是关于如何为 JSF 自定义组件动态生成 CSS的主要内容,如果未能解决你的问题,请参考以下文章
关于 JSF 2.0 自定义组件和 Primefaces 的帮助