JSF2.0实战 - 8、实现换肤功能

上几篇开发的Button和TextBox组件,一直采用的是claro皮肤,代码是固定写死的:

@ResourceDependency(library = "dijit/themes/claro", name = "claro.css", target = "head") })  

<body class="claro">

因为所有的组件都存在换肤需要,所以在继续开发更多组件以前,我先解决换肤问题。上一篇实现了自定义<h:head>以后,换肤就好办了,只需要<head>中加入换皮肤所需的css,并在页面加载时设置body的class,就可以实现换肤了。

修改HeadRenderer.java

package org.dojo4j.component;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.FacesRenderer;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@FacesRenderer(componentFamily = Head.COMPONENT_FAMILY, rendererType = Head.COMPONENT_TYPE)
//直接继承com.sun.faces.renderkit.html_basic.HeadRenderer,修改部分渲染代码
public class HeadRenderer extends com.sun.faces.renderkit.html_basic.HeadRenderer {

	public static final String THEME_KEY = "dojo4j.theme";
	public static final String DEFAULT_THEME = "claro";
	private String theme = null;
	
	@Override
	public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
		HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
		ResponseWriter writer = context.getResponseWriter();
		
		//加入dojo.css引用,因为每个dojo组件都需要dojo.css支持,所以加到head里避免重复生成
		writer.startElement("link", component);
		writer.writeAttribute("type", "text/css", null);
		writer.writeAttribute("rel", "stylesheet", null);
		writer.writeAttribute("href", request.getContextPath() + context.getExternalContext().getRequestServletPath()
				+ "/javax.faces.resource/dojo/resources/dojo.css", null);
		writer.endElement("link");
		
		//加入皮肤.css引用
		this.theme = getTheme(context);
		writer.endElement("link");
		writer.startElement("link", component);
		writer.writeAttribute("rel", "stylesheet", null);
		writer.writeAttribute("href", request.getContextPath() + context.getExternalContext().getRequestServletPath()
			+ "/javax.faces.resource/dijit/themes/" + this.theme + "/" + this.theme + ".css", null);
		writer.endElement("link");
		
		//加入dojo.js引用,因为每个dojo组件都需要dojo.js支持,所以加到head里避免重复生成
		writer.startElement("script", component);
		writer.writeAttribute("type", "text/javascript", null);
		writer.writeAttribute("src", request.getContextPath() + context.getExternalContext().getRequestServletPath()
				+ "/javax.faces.resource/dojo/dojo.js", null);
		writer.writeAttribute("data-dojo-config", "async: true, parseOnLoad: true", null);
		writer.endElement("script");
		encodeHeadResources(context, component);
		writer.endElement("head");//writer.startElement("head");在父类的encodeBegin里
	}
	
	//获取皮肤参数并设置到cookie中
	public static String getTheme(FacesContext context) {
		HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
		String theme = request.getParameter(THEME_KEY);
		if (theme == null || theme.trim().length() < 1) {
			Cookie[] cookies = request.getCookies();
			if (cookies != null && cookies.length > 0) {
				for (int i=0;i<cookies.length;i++) {
					Cookie cookie = cookies[i];
					if (THEME_KEY.equals(cookie.getName())) {
						theme = cookie.getValue();
						break;
					}
				}
			}
		}
		if (theme == null || theme.trim().length() < 1) {
			theme = DEFAULT_THEME;
		}
		HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();
		response.addCookie(new Cookie(THEME_KEY, theme));
		return theme;
	}
	
	private void encodeHeadResources(FacesContext context, UIComponent component) throws IOException {
		ResponseWriter writer = context.getResponseWriter();
		
		List<String> requires = new ArrayList<String>();
		//require加入必需的dojo/parser
		requires.add("dojo/parser");
		//解决皮肤切换需求
		requires.add("dojo/dom-class");

		UIViewRoot viewRoot = context.getViewRoot();
		for (UIComponent resource : viewRoot.getComponentResources(context, "head")) {
			Map<String, Object> attributes = resource.getAttributes();
			String name = (String) attributes.get("name");
			
			//把引用的dojo库中的js文件,转换成require写法,不引入js文件
			if (name.startsWith("dojo/") || name.startsWith("dijit/") || name.startsWith("dojox/")) {
				if (name.endsWith(".js")) {
					String path = name.substring(0, name.lastIndexOf("."));
					if (!requires.contains(path))
						requires.add(path);
					continue;
				}
			}
			resource.encodeAll(context);
		}

		//生成dojo require方式的代码
		writer.startElement("script", component);
		writer.write("require([");
		String tmp = "";
		for (int i = 0; i < requires.size(); i++) {
			writer.write(tmp + "\"" + requires.get(i) + "\"");
			tmp = ", ";
		}
		////解决皮肤切换需求
		writer.write(", \"dojo/domReady!\"], function(parser, domClass) {");
		writer.write("domClass.add(document.body, \"" + this.theme + "\");");
		writer.write("});");
		writer.endElement("script");
	}
}

删除ButtonRenderer.java和TextBoxRenderer.java中的代码:

@ResourceDependency(name = "dijit/themes/claro/claro.css", target = "head"), 

将buttonTest.xhtml和textBoxTest.xhtml中的<body class="claro">改成<body>

这样改了以后,在首次访问页面时,会加载默认皮肤claro,可以通过在请求中加入dojo4j.theme=xxx改变皮肤,改了以后会保存在cookie中,持续有效。目前dojo提供的皮肤有四种:claro,tundra,soria,nihilo

JSF2.0实战 - 8、实现换肤功能_第1张图片

JSF2.0实战 - 8、实现换肤功能_第2张图片

JSF2.0实战 - 8、实现换肤功能_第3张图片

查看生成的页面源代码可以看到发生的变化:

<link rel="stylesheet" href="/dojo4j/faces/javax.faces.resource/dijit/themes/tundra/tundra.css" />

<script>
	require([ "dojo/parser", "dojo/dom-class", "dijit/form/TextBox",
			"dijit/form/Button", "dojo/domReady!" ],
			function(parser, domClass) {
				domClass.add(document.body, "tundra");
			});
</script>

下载代码

你可能感兴趣的:(框架,前端,JSF,dojo,JSF2.0)