VTemplate模板引擎的使用--进阶篇

1、<vt:template>与<vt:include>标签的不同

<vt:template>和<vt:include> 标签都包含file属性,如果这两个标签都设置file属性,那这两个标签看起来很相似,并且最终效果都是将文件的内容包含进来。但是对于模板引擎来说它们之间的差别却是非常的大。

<vt:template>标签是“模板块”标签,它能拥有自己的“变量”,它会成为它内部的标签的“宿主模板”(OwnerTemplate)。而<vt:include>则只是简单的将文件内容包含进来,它内部的标签的“宿主模板”与它相同。

现假如有一个VT模板文件: inc_content.html

我是包含文件里的变量 {$:#.var1}。 
我是包含文件里的foreach标签: 
<vt:foreach from=”$#.names” item=”#.name” index=”#.i”> 
包含文件的第{$:#.i}个名字叫{$:#.name}。 
</vt:foreach>

现分别用<vt:template> 和 <vt:include>标签去包含上面的文件,如下: 

A、<vt:template>包含:

我是外部的变量{$:#.var1}。 
我是外部的foreach标签: 
<vt:foreach from=”$#.names” item=”#.name” index=”#.i”> 
外部的第{$:#.i}个名字叫{$:#.name}。 
</vt:foreach> 
<vt:template id=”inc” file=”inc_content.html” />


B、<vt:include>包含:

我是外部的变量{$:#.var1}。 
我是外部的foreach标签: 
<vt:foreach from=”$#.names” item=”#.name” index=”#.i”> 
外部的第{$:#.i}个名字叫{$:#.name}。 
</vt:foreach> 
<vt:include id=”inc” file=”inc_content.html” />


上面两块的VT模板代码看起来很相似,但是经解析后A中的var1与inc这个<vt:template>模板块下的变量var1分别独立存在,互不影响!而B中的变量var1与inc这个<vt:include>的变量var1相等,都是引用同一个变量(其它变量类似)。

现假如A、B两块的VT模板代码都通过过下面的程序来处理:

this.Document.Variables.SetValue("var1", 1); 
this.Document.Variables.SetValue("names", new string[] { "张三", "李四", "王五" });


也即是只对外部变量var1、names赋值,最终经模板引擎解析输出后,它们的输出结果如下: 
VTemplate模板引擎的使用--进阶篇

从图可知,<vt:template>包含的没有数据输出,而用<vt:include>包含则有数据输出并且和外部数据一模一样!所以可把<vt:template>标签看成是程序语言里的类,它能拥有它自己的变量,改变外部变量的值不会影响到其内部的同名变量,并且外部标签可通过其id获取其内部变量!

具体的示例代码,请参考:http://net-vtemplate.googlecode.com/svn/src/VTemplate.WebTester/template_include_test.ashx.cs

 

 

2、使用变量表达式

变量表达式可用在标签属性,也可用在变量元素中。它的作用就是用于获取变量中某个字段、属性、函数方法或索引的结果值。比如上例中的#.var1就是说明获取var1变量的值,也即是数值“1”。

对于变量值类型中真实存在的字段、属性或函数方法,VT模板引擎将通过反射获取其结果值,例如以下VT模板代码:

我叫{$:user.name},今年{$:user.age}岁,我来自{$:user.location.getcity()}


假如对user变量赋以下类实例的值,那么上面模板代码解析时模板引擎将能正确解析出各个变量表达式的最终值。

class Location 
{    
    public string GetCity(){ 
         //code here 
    } 
}

class User 

    public string Name { get; set; } 
    public int Age { get; set; } 
    public Location Location { get; set; } 
}

但在某些情况下,我们需要获取的“值”并不简单地存在变量值的类型中,而是需要经过其它处理运算得出来的值。比如上面的获取个人资料里,我们还要获取用户的个人财产总额,但从上面的代码里可看出个人财产总额项并不存在于User类里,所以导致VT模板引擎根本无法获取此项的值。那我们要如何做才能获取此项数据呢?VT模板引擎提供了一个手动设置变量表达式的值的方法,而我们要做的就是根据此方法手动设置变量表达式的值!例如上面的VT模板代码改为如下:

我叫{$:user.name},今年{$:user.age}岁,我来自{$:user.location.getcity()},我的个人财产总共有{$:user.totalmoney}元。

从上面的类实例代码中可知道totalmoney这个项是不存在User的属性/字段列表里的,所以我们就要手动设置{$:user.totalmoney}的值,示例代码如下:

/// <summary> 
/// 返回某个用户的个人财产总额 
/// </summary> 
/// <param name="user"></param> 
/// <returns></returns> 
static int GetUserTotalMoney(User user) 

    //code here 


//------------------------使用代码----------------------------------------//

//获取user变量 
Variable userVar = this.Document.Variables["user"]; 
//生成User实例 
User user = new User(); 
//…………其它代码略去…………// 
//设置user变量的值为User实例 
userVar.Value = user; 
//手动设置totalmoney的值(注意,这行和上面那行的顺序不能搞乱) 
userVar.SetExpValue("totalmoney", GetUserTotalMoney(user));

 

 

3、有条件的控制数据的输出

在输出数据时,我们并不是简单的输出所有数据,而是要根据外部的许多条件组合获取其中的部分数据。而对于这些外部条件,如果可固定的则我们可以在设计VT模板时将其写入到标签(建议是<vt:template>标签)的属性里,这样我们就能在程序代码里获取到这些外部条件并加以处理数据。

例如博客园的新闻频道里右边的“相关新闻”、“热点新闻”两栏数据,如下图:

VTemplate模板引擎的使用--进阶篇

假设“相关新闻”里获取的新闻是属于"relating”类型的新闻,而“热点新闻”则是获取属于"hoting”类型的新闻,则我们可以设计其VT模板如下:

<div class="side_block"> 
  <h3 class="title_blue">相关新闻</h3> 
  <vt:template name="topnews" type="relating" file="cnblogs_newsdata.html" /> 
</div> 
<div class="side_block"> 
  <h3 class="title_yellow">热点新闻</h3> 
  <vt:template name="topnews" type="hoting" file="cnblogs_newsdata.html" /> 
</div>

在上面的VT模板中,定义了两个name为"topnews”的<vt:template>标签,这是为了便于在代码里对这两个<vt:template>进行统一处理(因为它们要处理的数据都是相同,只是获取数据条件不同)而定义的名称。并且分别定义了自定义属性type用于做数据获取条件。其中包含文件cnblogs_newsdata.html的VT模板如下:

<ul class="topnews block_list bt"> 
  <vt:foreach from="$#.newsdata" item="#.news" index="#.i" id="newslist"> 
  <li> 
    <a href="{$:#.news.url}" title="{$:#.news.title htmlencode='true'}">{$:#.news.title htmlencode='true'}...</a> 
  </li> 
  </vt:foreach> 
</ul>

在此文件的VT模板中,定义了一个id为"newslist"的<vt:foreach>标签,定义此id是为了在程序代码里控制新闻的输出和处理每条新闻的访问地址,也即是"{$:#.news.url}”变量表达式的值。

示例代码:

//获取所有名称为topnews的模板块 
ElementCollection<Template> templates = this.Document.GetChildTemplatesByName("topnews"); 
foreach (Template template in templates) 

    //根据模板块里定义的type属性条件取得新闻数据 
    List<News> newsData = GetNewsData(template.Attributes.GetValue("type")); 
    //设置变量newsdata的值 
    template.Variables.SetValue("newsdata", newsData);

    //取得模板块下Id为newslist的标签(也即是在cnblogs_newsdata.html文件中定义的foreach标签) 
    Tag tag = template.GetChildTagById("newslist"); 
    if (tag is ForEachTag) 
    { 
        //如果标签为foreach标签则设置其BeforeRender事件用于设置变量表达式{$:#.news.url}的值 
        tag.BeforeRender += (sender, e) => 
        { 
            ForEachTag t = (ForEachTag)sender; 
            //取得当前项的值(因为foreach标签的数据源是List<News>集合,所以当前项的值类型为News实体) 
            News news = (News)t.Item.Value; 
            //设置当前项的变量表达式的值.也即是"{$:#.news.url}"变量表达式 
            t.Item.SetExpValue("url", GetNewsUrl(news)); 
        }; 
    } 
}

在上面代码中使用了BeforeRender事件,此事件是在标签元素的数据呈现之前触发。对于循环元素<vt:foreach>和<vt:for>,因为每次循环时都会呈现数据,也就导致每次循环时都会触发此事件(包括AfterRender事件),所以我们就可通过此事件方法获取到循环当前项的值。

具体的示例代码,请参考:http://net-vtemplate.googlecode.com/svn/src/VTemplate.WebTester/cnblogs_newslist.ashx.cs

 

VTemplate项目托管在Google code上。 
URL: http://net-vtemplate.googlecode.com/ 
SVN: http://net-vtemplate.googlecode.com/svn/src/VTemplate.Engine/

更多例子请参考VTemplate.WebTester项目

http://net-vtemplate.googlecode.com/svn/src/VTemplate.WebTester/

 

或观看在线演示例子:(感谢网友“DOLT”、疯子” 提供

http://61.155.39.222:8888/index.ashx

 

注:已建立VTemplate模板引擎技术交流QQ群,欢迎各位加入参与项目开发或技术探讨。QQ群:884468

上一篇:volatile踩坑实例


下一篇:[ 转载 ] Java基础