GXT之旅:第六章:Templates(1)——Template(2)

Template

通过使用Template类,可以定义一组html的字符串去渲染ModelData或者Params。其生成的html 字符串里面可以设置占位符,要来作为变量可以设置参数。

一个占位符参数的定义,需要通过{}给包裹起来。一个使用firstName和lastName定义的Template如下:

Template template = new Template("My full name is {firstName} {lastName}.");
接下来,我们需要Params给占位符参数设值

Params data = new Params();
data.set("firstName", "Daniel");
data.set("lastName", "Vaughan");
最后,让template应用data(Params)的值域,需要通过applyTemplate方法

template.applyTemplate(data);

Template可以被预编译,这样就可以节约头期使用正规表达式的时间。实现此功能需要调用Template.compile方法。

在RSSReader项目里,我们要自定义组件——ItemPanel 用来使用Template将一个对象渲染成html。

  • 在com.danielvaughan.rssreader.client.components包下,新建ItemPanel extends ContentPanel
package com.danielvaughan.rssreader.client.components;

import com.extjs.gxt.ui.client.widget.ContentPanel;

public class ItemPanel extends ContentPanel {

}
  • 新建一个属性——GWT的HTML widget
private final HTML html = new HTML();
  • 当然要override onRender方法——设置标题,并将HTMl加入到ContentPanel里
	@Override
	protected void onRender(Element parent, int index) {
		super.onRender(parent, index);
		setHeading("Item");
		add(html);
	}
  • 继续在onRender方法里——因为我们希望让ContentPanel能够自适应HTML widget的大小,所以要设置成FitLayout布局方式。当然我们同样的希望设置HTML widget应用一个CSS style,这样我们就可以编辑其样式,来设置HTML的显示方式:
	@Override
	protected void onRender(Element parent, int index) {
		super.onRender(parent, index);
		setHeading("Item");
		setLayout(new FitLayout());
		html.setStylePrimaryName("item");
		add(html);
	}
  • 接下来,我们构造template的字符串——Template接收的是一个String类型的字符串,我们可以使用java标准的StringBuilder类来生成String。我们将占位符参数通过大括号包裹起来。
	private String getTemplate() {
		StringBuilder sb = new StringBuilder();
		sb.append("<h1>{title}</h1>");
		sb.append("<p><i>{pubDate}</i></p>");
		sb.append("<hr/>");
		sb.append("<img src=\"{thumbnailUrl}\"/>");
		sb.append("<p>{description}</p>");
		return sb.toString();
	}
  • 新建一个方法displayItem——它会有一个参数为Item。将Item对象里面属性存储的值,赋值给template的占位符,根据item的属性名称和template里占位符的属性名称一一对应。此操作GXT已经给我们提供了Util类,具体实现如下:
	public void displayItem(Item item) {

		setHeading(item.getTitle());
		Template template = new Template(getTemplate());
		html.setHTML(template.applyTemplate(Util.getJsObject(item, 1)));
	}
  • 下面在程序的入口html文件里(RSSReader.html),引用新建的css文件(css/item.css)
<link type="text/css" rel="stylesheet" href="css/item.css">
  • 在item.css样式文件里,定义相关其template设置的html标记的样式。
.item h1 {
	font-size: 1.5em;
}

.item img {
	border: 1px solid #000;
	float: left;
	margin-right: 10px;
}

.item hr {
	border-bottom: 1px solid #000;
}
  • 我们现在需要新建一个测试类去实验,让ItemPanel显示item对象的template。在com.danielvaughan.rssreader.client包下,新建TestObjects类,具体实现如下:
package com.danielvaughan.rssreader.client;

import java.util.Date;

import com.danielvaughan.rssreader.shared.model.Item;

public class TestObjects {
	public static Item getTestItem() {
		Item testItem = new Item();
		testItem.setTitle("Computers get more powerful");
		testItem
				.setDescription("New computers are more powerful "
						+ "than the computers that were around a year ago. "
						+ "They are also much more powerful than the computers from five years ago. "
						+ "If you were to compare current computers with the computers of twenty "
						+ "years ago you would fine they are far more powerful.");
		testItem.setLink("http://www.example.com/item573.html");
		testItem.setPubDate(new Date());
		testItem.setCategory("Category");
		testItem
				.setThumbnailUrl("http://localhost:8888/computers.jpg");
		return testItem;
	}
}
  • 在RSSReader类里,将ItemPanel替换RssMainPanel

//RssMainPanel mainPanel = new RssMainPanel();
ItemPanel mainPanel = new ItemPanel();
mainPanel.displayItem(TestObjects.getTestItem());

  • 显示效果如下:


在其他components里使用Templates

不单单HTML widget可以使用Template,其他的components也可以使用Template去定义HTML。具体来说,ListField,ComboBox,ToolTipConfig都可以使用Template。

当我们使用ListField或ComboBox的时候,Template的使用是去定义其里面的列表item。例如,使用Template定义多个fields的组合显示,去替换ListField里面的单一的field显示。但是要注意,因为ListField或ComboBox里面都是使用ModelData的结果集,因此需要针对每一个item设置其Template。

Template有一个专门的标签<tpl>,此标记提供一个方法去迭代list组件里面每一个item的,并赋予其template。在了解XTemplate之前,我们会详细了解<tpl>标记的使用。

随着时间的推移,我们会不断的修改RSSReader项目里面FeedList类,让其显示Feed对象里name和部分description内容,取代之前仅仅是显示name字段。虽然我们使用ListField举例,但是其操作过程同样应用与ComboBox component。

  • 我们在FeedList类里面,定义一个getTemplate方法,用来返回Template形式的字符串
  • 在此方法里,我们需要使用<tpl>用于加工store里面的每个ModelData。

	private String getTemplate() {
		StringBuilder sb = new StringBuilder();
		sb.append("<tpl for=\".\">");
		sb.append("</tpl>");
		return sb.toString();
	}

  • 在<tpl>标记之间,我们使用<div>标签来包裹这每一行的显示效果,其css style设置成“x-combo-list-item”

	private String getTemplate() {
		StringBuilder sb = new StringBuilder();
		sb.append("<tpl for=\".\">");
		sb.append("<div class='x-combo-list-item'><b>{title}</b> -{description}</div>");
		sb.append("</tpl>");
		return sb.toString();
	}

  • ListField同样提供setTemplate方法——在FeedList类中,onRender方法内,替换setDisplayField方法。

		//feedList.setDisplayField("title");
		feedList.setTemplate(getTemplate());

  • 修改后的整个FeedList类如下:

package com.danielvaughan.rssreader.client.lists;

import java.util.List;

import com.danielvaughan.rssreader.client.RSSReaderConstants;
import com.danielvaughan.rssreader.client.services.FeedServiceAsync;
import com.danielvaughan.rssreader.shared.model.Feed;
import com.extjs.gxt.ui.client.Registry;
import com.extjs.gxt.ui.client.data.BaseListLoader;
import com.extjs.gxt.ui.client.data.BeanModel;
import com.extjs.gxt.ui.client.data.BeanModelReader;
import com.extjs.gxt.ui.client.data.ListLoadResult;
import com.extjs.gxt.ui.client.data.ListLoader;
import com.extjs.gxt.ui.client.data.LoadEvent;
import com.extjs.gxt.ui.client.data.RpcProxy;
import com.extjs.gxt.ui.client.event.LoadListener;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.form.ListField;
import com.extjs.gxt.ui.client.widget.layout.FitLayout;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.rpc.AsyncCallback;

public class FeedList extends LayoutContainer {
	private final ListStore<BeanModel> feedStoreR = Registry
			.get(RSSReaderConstants.FEED_STORE);

	public FeedList() {
		setLayout(new FitLayout());
	}

	private String getTemplate() {
		StringBuilder sb = new StringBuilder();
		sb.append("<tpl for=\".\">");
		sb.append("<div class='x-combo-list-item'><b>{title}</b> -{description}</div>");
		sb.append("</tpl>");
		return sb.toString();
	}

	@Override
	protected void onRender(Element parent, int index) {
		super.onRender(parent, index);
		final ListField<BeanModel> feedList = new ListField<BeanModel>();
		// 0:从Registry里获得Service
		final FeedServiceAsync feedService = (FeedServiceAsync) Registry
				.get(RSSReaderConstants.FEED_SERVICE);
		// 1:定义proxy在load方法里掉用Serivce里的方法
		RpcProxy<List<Feed>> proxy = new RpcProxy<List<Feed>>() {
			@Override
			protected void load(Object loadConfig,
					AsyncCallback<List<Feed>> callback) {
				feedService.loadFeedList(false, callback);

			}
		};
		// 2:定义Reader
		BeanModelReader reader = new BeanModelReader();
		// 3:将proxy和reader传入,定义loader
		ListLoader<ListLoadResult<BeanModel>> loader = new BaseListLoader<ListLoadResult<BeanModel>>(
				proxy, reader);
		// 4:传入loader,生成store,此时还没有load数据
		final ListStore<BeanModel> feedStore = new ListStore<BeanModel>(loader);
		// 5:将stroe绑定到data-backed component身上
		feedList.setStore(feedStoreR);
		//feedList.setDisplayField("title");
		feedList.setTemplate(getTemplate());
		// 6:真正的load数据,load成功之后,data-backed component会自动的显示出来。
		loader.load();

		loader.addLoadListener(new LoadListener() {
			@Override
			public void loaderLoad(LoadEvent le) {
				feedStoreR.add(feedStore.getModels());

			}
		});

		add(feedList);
	}
}

  • 运行效果如下:



  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值