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

来源:互联网 发布:vip域名可以备案吗 编辑:程序博客网 时间:2024/05/29 07:00

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里
@Overrideprotected void onRender(Element parent, int index) {super.onRender(parent, index);setHeading("Item");add(html);}
  • 继续在onRender方法里——因为我们希望让ContentPanel能够自适应HTML widget的大小,所以要设置成FitLayout布局方式。当然我们同样的希望设置HTML widget应用一个CSS style,这样我们就可以编辑其样式,来设置HTML的显示方式:
@Overrideprotected 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();}@Overrideprotected void onRender(Element parent, int index) {super.onRender(parent, index);final ListField<BeanModel> feedList = new ListField<BeanModel>();// 0:从Registry里获得Servicefinal FeedServiceAsync feedService = (FeedServiceAsync) Registry.get(RSSReaderConstants.FEED_SERVICE);// 1:定义proxy在load方法里掉用Serivce里的方法RpcProxy<List<Feed>> proxy = new RpcProxy<List<Feed>>() {@Overrideprotected void load(Object loadConfig,AsyncCallback<List<Feed>> callback) {feedService.loadFeedList(false, callback);}};// 2:定义ReaderBeanModelReader reader = new BeanModelReader();// 3:将proxy和reader传入,定义loaderListLoader<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() {@Overridepublic void loaderLoad(LoadEvent le) {feedStoreR.add(feedStore.getModels());}});add(feedList);}}

  • 运行效果如下:



原创粉丝点击