第一部分:源码
AbstractConditional.java
// Copyright 2009 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package org.apache.tapestry5.corelib.base; import org.apache.tapestry5.BindingConstants; import org.apache.tapestry5.Block; import org.apache.tapestry5.ComponentResources; import org.apache.tapestry5.MarkupWriter; import org.apache.tapestry5.annotations.Parameter; import org.apache.tapestry5.annotations.SupportsInformalParameters; import org.apache.tapestry5.ioc.annotations.Inject; /** * Base class for {@link org.apache.tapestry5.corelib.components.If} and {@link org.apache.tapestry5.corelib.components.Unless}. * Will render its body or the block from its else parameter. If it renders anything and it has an element name, then * it renders the element and its informal parameters. */ @SupportsInformalParameters public abstract class AbstractConditional { @Inject private ComponentResources resources; /** * Performs the test via the parameters; return true to render the body of the component, false to render the else * block (or nothing). * * @return true to render body */ protected abstract boolean test(); /** * An alternate {@link org.apache.tapestry5.Block} to render if {@link #test()} is false. The default, null, means * render nothing in that situation. */ @Parameter(name = "else", defaultPrefix = BindingConstants.LITERAL) private Block elseBlock; private boolean renderTag; /** * Returns null if the {@link #test()} is true, which allows normal rendering (of the body). If the test parameter * is false, returns the else parameter (this may also be null). */ Object beginRender(MarkupWriter writer) { Block toRender = test() ? resources.getBody() : elseBlock; String elementName = resources.getElementName(); renderTag = toRender != null && elementName != null; if (renderTag) { writer.element(elementName); resources.renderInformalParameters(writer); } return toRender; } /** * If {@link #test()} is true, then the body is rendered, otherwise not. The component does not have a template or * do any other rendering besides its body. */ boolean beforeRenderBody() { return false; } void afterRenderBody(MarkupWriter writer) { if (renderTag) writer.end(); } }
If.java
// Copyright 2006, 2007 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package org.apache.tapestry5.corelib.components; import org.apache.tapestry5.annotations.Parameter; import org.apache.tapestry5.corelib.base.AbstractConditional; /** * Conditionally renders its body. May render its tag and any informal parameters. */ public class If extends AbstractConditional { /** * If true, then the body of the If component is rendered. If false, the body is omitted. */ @Parameter(required = true) private boolean test; /** * Optional parameter to invert the test. If true, then the body is rendered when the test parameter is false (not * true). * * @see Unless */ @Parameter private boolean negate; /** * @return test parameter (if negate is false), or test parameter inverted (if negate is true) */ protected boolean test() { return test != negate; } }
Unless.java
// Copyright 2008 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package org.apache.tapestry5.corelib.components; import org.apache.tapestry5.annotations.Parameter; import org.apache.tapestry5.corelib.base.AbstractConditional; /** * A close relative of the {@link org.apache.tapestry5.corelib.components.If} component that inverts the meaning of its * test. This is easier than an If component with the negate parameter set to true. */ public class Unless extends AbstractConditional { /** * If true, then the body of the If component is rendered. If false, the body is omitted. */ @Parameter(required = true) private boolean test; /** * @return test parameter inverted */ protected boolean test() { return !test; } }
第二部分:简介
<t:if/>和<t:unless/>是条件判断组件,使用test属性指定要测试的条件,然后决定渲染的部分,如果test为真则渲染
<t:if/>的内部非<p:else>部分,如果test属性的结果是假,那么渲染<p:else>部分或者else属性指定的字符串、block或者
其他部分,test的测试结果的作用可以使用negate来做反转,是渲染效果相反,如果negate属性为真,那么<t:if/>和
<t:unless/>就是等效的test渲染结果。
<t:unless/>的使用就是相比较<t:if/>更加简单,可以自己试一下了。
第三部分:测试
以下是测试用的最终代码文件
Start.tml
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd" xmlns:p="tapestry:parameter"> <head> <title>t:if and t:unless</title> </head> <body> <t:if test="'field'">not use field<br/></t:if> <hr/> <t:if test="test1" else="block:testfalse"> Test1 t:block True<br/> </t:if> <t:block id="testfalse"> Test1 t:block False<br/> </t:block> <hr/> <t:if test="test1" > Test1 p:else True<br/> <p:else> Test1 p:else False<br/> </p:else> </t:if> <hr/> <span t:type="if" t:test="test2">test2 span</span> <hr/> <t:if test="test2" negate="true"> Test2 negate True<br/> <p:else> Test2 negate False<br/> </p:else> </t:if> <hr/> <t:if test="test2" negate="false"> Test2 negate True<br/> <p:else> Test2 negate False<br/> </p:else> </t:if> <hr/> <t:if test="test3"> Test3 "" True<br/> <p:else> Test3 "" False<br/> </p:else> </t:if> <hr/> <t:if test="test4"> Test4 "false" True<br/> <p:else> Test4 "false" False<br/> </p:else> </t:if> <hr/> <t:if test="test5"> Test5 "0" True<br/> <p:else> Test5 "0" False<br/> </p:else> </t:if> <hr/> <t:if test="test6"> Test6 int 0 True<br/> <p:else> Test6 int 0 False<br/> </p:else> </t:if> <hr/> <t:if test="test7"> Test7 int 7 True<br/> <p:else> Test7 int 7 False<br/> </p:else> </t:if> <hr/> <t:if test="test8"> Test8 <![CDATA[List<Integer>]]]>=null True<br/> <p:else> Test8 <![CDATA[List<Integer>]]]>=null False<br/> </p:else> </t:if> <hr/> <t:if test="test9"> Test9 <![CDATA[List<Integer>]]]> size=0 True<br/> <p:else> Test9 <![CDATA[List<Integer>]]]> size=0 False<br/> </p:else> </t:if> <hr/> <t:if test="test10"> Test10 <![CDATA[List<Integer>]]]> size=2 True<br/> <p:else> Test10 <![CDATA[List<Integer>]]]> size=2 False<br/> </p:else> </t:if> <hr/> <t:if test="test11"> Test12 Object=null True<br/> <p:else> Test12 Object=null False<br/> </p:else> </t:if> <hr/> <t:if test="test12"> Test13 Object!=null True<br/> <p:else> Test13 Object!=null False<br/> </p:else> </t:if> <hr/> </body> </html>
Start.java
package jumpstart.web.pages; import java.util.ArrayList; import java.util.List; import jumpstart.web.data.Person; import org.apache.tapestry5.annotations.Property; public class Start { @Property private boolean test1 = false; @Property private boolean test2 = true; @Property private String test3 = ""; @Property private String test4 = "false"; @Property private String test5 = "0"; @Property private int test6 = 0; @Property private int test7 = 2; @Property private List<Integer> test8; @Property private List<Integer> test9 = new ArrayList<Integer>(); @Property private List<Integer> test10 = new ArrayList<Integer>() { { add(1); add(2); } }; @Property private Person test11; @Property private Person test12 = new Person(); }
最终的效果
最终的效果(HTML)
<body> not use field<br/> <hr/> Test1 t:block False<br/> <hr/> Test1 p:else False<br/> <hr/> <span>test2 span</span> <hr/> Test2 negate False<br/> <hr/> Test2 negate True<br/> <hr/> Test3 "" False<br/> <hr/> Test4 "false" False<br/> <hr/> Test5 "0" True<br/> <hr/> Test6 int 0 False<br/> <hr/> Test7 int 7 True<br/> <hr/> Test8 List<Integer>]=null False<br/> <hr/> Test9 List<Integer>] size=0 False<br/> <hr/> Test10 List<Integer>] size=2 True<br/> <hr/> Test12 Object=null False<br/> <hr/> Test13 Object!=null True<br/> <hr/> </body>
第四部分:分析
代码中if和unless两个类都是继承自AbstractConditional抽象类,在抽象类中声明了一个protected abstract boolean
test();该方法在if和unless中有不同的实现,返回值正好是相反,这也就成就了if和unless的test属性不同渲染结果。
Object beginRender(MarkupWriter writer)
{
Block toRender = test() ? resources.getBody() : elseBlock;
String elementName = resources.getElementName();
renderTag = toRender != null && elementName != null;
if (renderTag)
{
writer.element(elementName);
resources.renderInformalParameters(writer);
}
return toRender;
}
上述这段代码,首先根据test()的结果,来决定渲染的toRender是if(或者unless)所在标签的内容还是else属性指定的
block,然后下面就正常渲染if(或者unless)的elementName(就是使用<elementName t:type="if" test="'field'"/>格式
书写)。
negate的反转效果就是在实现抽象类AbstractConditional的test()方法的时候使用了一个反转判断效果。