treefrog之视图 Otama模版系统

Otama模版系统

Otama模版系统系统将界面逻辑从模版中完全分离出来..它是专门为Treefrog框架设计的.当配置文件(development.ini)按下面这样编辑后使用生成器生成程序骨架时, 将创建Otama系统的视图.

TemplateSystem=Otama

模版完全由HTML写成(使用.html作为后缀名).一个”标记”用来标识逻辑代码应该插入的元素.界面逻辑文件(.otm)由C++和标记写成.当共享的视图(view)库构建时,这些会被自动转换成C++代码.

视图(View)转换

基本上, 每个操作(action)会生成一对页面逻辑和模版.文件名为[操作名(action name)].html和[操作名(action name)].otm(大小写敏感).这些文件保存在”views/controller-name/”文件夹内.一旦你创建了一个新模版, 为了将这些反馈到视图(view)的共享库中, 你需要在view目录下运行”make qmake”.

$ cd views
$ make qmake

如果没有这样做, 检验在继续这一章时先阅读ERB章节, 因为两个模版系统有很多相同的地方.还有, 关于Otama系统有很多内容要学习, 先学会ERB将更容易理解Otama.

输出字符串

我们将要输出字符串”Hello world.
”在用HTML写的模版页, 使用一个叫data-tf的自定义属性, 然后为元素设置一个”标记(mark).”属性的名字必须以”@”打头.举例, 我们这样写:

<p data-tf="@hello"></p>

我们使用段落标签(<p> </p>)包住@hello标记.
在标记中,只可以使用字母和下划线’_‘.不要使用其他字符.接下来我们来看一些C++代码中的界面逻辑.我们需要将C++代码和上面使用的b标记关联起来.我们这样写:

@hello ~ eh("Hello world");

当构建的时候, 运行应用, 视图(view)即将会输出下面的结果:

<p>Hello world</p>

波浪号(~) 通过界面逻辑使用的标记连接C++代码表示”标记元素的内容被取代右侧内容取代”.记住eh()方法输出的值被传递了.换句话说, 在P标签中的内容(这个例子为空)被”Hello world”替换了.data-tf属性将完全消失.此外, 还有一个替代的方法输出同样的内容, 它也可以这样写:

@hello ~= "Hello world"

和ERB中一样, ~和eh()方法的组合可以被写成’~=’, ~和echo()方法的组合可以写成’~==’.虽然, 为了简单解释,我们在这里输出了一个静态的字符串, 其实它可以用同样的方式输出一个变量. 当然, 它也可以输出从控制器(controller)传递的对象.

概要: 在想要输出变量的地方放置标记(mark).然后连接mark到代码.

Otama操作符

夹在C++代码和标记(mark)找那个的符号叫做Otama操作符.C++代码和元素用Otama操作符结合, 然后决定它们应该如何工作.在界面逻辑, 要注意Otama操作符的两侧必须有一个空格.这次, 我们使用一个不同的Otama操作符.让我们假设逻辑界面是这样写的(冒号).

@hello : eh("Hello world");

视图的结果是这样的:

Hello world

P标签被删除了.这是因为冒号用结果”更换整个标记(maked)的元素”.类似上面的内容, 这个也可以这样写:

@hello := "Hello world"

使用从控制器(controller)传递来的对象

为了显示从控制器(controller)导出的对象, 和ERB一样, 你可以用tfetch()宏或者T_FETCH宏获取后再使用它.当msg可以导出为QString类型的变量时, 你可以这样写:

@hello : tfetch(QString, msg);  eh(msg);

和ERB一样, 获取(fetched)的对象被定义为局部变量.通常, C++代码不适合写在一行.要给一个标记(mark)写多行的C++代码, 可以像平常一样写但是要在每行后放置一个空行.这个空行会被当成一个标记(mark)的一部分.这样, 在一个标记(mark)和另外一个空行(包括只有一个空字的行)表现为界面逻辑的分割器.

概要:逻辑通过一个空行进行界定.

接下来, 我们看看在两个不同的地方显示一个导出对象的例子.在这个例子中, 如果你把它写陈#init, 它将首先被获取(fetched)然后, 它可以在界面逻辑自由的使用.它应该看起来类似这样:

#init : tfetch(QString, msg);

@foo1 := msg

@foo2 ~= QString("message is ") + msg

像说过的那样, 要导出引用多次的对象, 在#init中进行获取(fetch).这里是另外一种方法导出对象.
在Otama操作符后面放置”$”.例如, 你可以写成下面这样导出名为obj1的对象.

@foo1 :=$ obj1

它表示obj1对象fetch()处理后,使用eh()输出值.然而, 这个处理过程等于获取(fetch)处理, 局部的变量事实上没有被定义.获得使用echo()方法的输出, 可以这样写:

@foo1 :==$ obj1

和ERB中一样.

概要:要导出对象,使用 =$ 或者~$.

循环

接下来, 我将接收如何使用循环重复显示列表的数字.
在模版中, 我们这样写.

<tr data-tf="@foreach">
  <td data-tf="@id"></ td>
  <td data-tf="@title"></ td>
  <td data-tf="@body"></ td>
</tr>

那些是名为blogList的Blog类的列表导出的对象.我们像给for语句写一个循环.这个while语句也是非常类似的.

@foreach :
tfetch(QList<Blog>, blogList);    /* 获取(fetch)处理 */
for (auto &b, blogList) {
  %%
}

@id ~= b.id()

@title ~= b.title()

@body ~= b.body()

銆€%%b标记是重要的, 因为它代表标记的整个元素(@foreach).换句话说, 这个例子中, 它代表从<tr>到</ tr>的元素.因此, 通过重复<tr>标签, 使用@id, @title, 和@body,设置每个内容元素的值的foreach语句在视图(view)中那个输出这样的结果:

<tr>
  <td>100</td>
  <td>Hello</td>
  <td>Hello world!</td>
</tr><tr>
  <td>101</td>
  <td>Good morning</td>
  <td>This morning ...</td>
</tr><tr>
   : (<-重复输出列表的对象)

和前面的一样, data-tf属性将会消失.

增加一个属性

让我们使用Otama操作符给一个元素增加属性.
假设你的模版找那个有这样的标记(mark):

<span data-tf="@spancolor">Message</span>

现在, 假设你在界面逻辑中这样写:

@spancolor + echo("class=\"c1\" title=\"foo\"");

下面是输出的结果:

<span class="c1" title="foo">Message</span>

通过使用+操作符, 你可以增加属性.
顺便提一句, 不可以使用eh()方法代替echo()方法, 因为双引号被转义后会是一个不同的意义.在界面逻辑中, 我们还可以用另外的一个方法写成这样:

@spancolor +== "class=\"c1\" title=\"foo\""

echo()方法可以重写成’==’.此外, 还可以写成这样,下面的替代方法输出同样的结果:

@spancolor +== a("class", "c1") | a("title", "foo")

a()方法创建一个表示HTML属性的THtmlAttribute对象, 使用|(竖线)来连接它们.连接后它不是一个THtmlAttribute对象, 但是如果你用echo()方法输出, 它们会被转换成key1=”val1”, key2=”val2” …这样的字符串, 作为结果添加到属性中.你愿意的话还可以添加更多属性.

重写<a>标签

可以使用冒号’:’操作符重写<a>标签.它像上面描述的一样.
回顾一下, <a>标签在模版中是这样标记(marked)的.

<a class="c1" data-tf="@foo">Back</a>

举例, 我们可以这样重写视图(view)(Blog的视图)的界面逻辑:

@foo :== linkTo("Back", urla("index"))

As a result, the view outputs the following:

<a href="/Blog/index/">Back</a>

因为linkTo()方法生成一个<a>标签, 我们可以得到这结果.不幸, 类原来的属性已经消失了.原因就是这个操作符有替换整个元素的效果.如果你想设置属性, 你可以增加一个参数到linkTo()方法.

@foo :== linkTo("Back", urla("index"), Tf::Get, "", a("class", "c1"))

类属性将会和上面的结果一样被输出.虽然属性信息可以被输出, 你肯定不会像在界面逻辑中麻烦地重写这些信息.
这里有个解决方法|==操作符.它有合并标签内容的同时保留属性的效果.所以, 让我们这样重写界面逻辑:

@foo  |== linkTo("Back", urla("index"))

视图(view)输出下面的结果:

<a class="c1" href="/Blog/index/">Back</a>

原来的类属性保留下来的, 没有消失.|== 操作符是有条件地合并元素.条件是元素必须是相同的标签.此外, 两者带有相同的属性, 界面逻辑的值优先级更高.通过使用这个操作符, 设计的信息(HTML属性)可以被转移到模版.

概要: 使用|==操作符保留模版设计的属性然后再合并.

说明:
只有|==操作符才可用, ‘|‘和’|=’都不能工作.

表单标签

不要是使用表单标签<form>来Post数据, 除非你已经打开跨域访问伪造(CSRF)监测.只有在模版中写表单标签, 才能接收Post数据.我们需要用隐藏的参数来嵌入秘密的信息.我们在模版中使用<form>标签.将标记(mark)放置在模版的<form>标签后, 然后用formTag()方法的输出作为内容进行合并.模版:

:
<form method="post" data-tf="@form">
:

界面逻辑:

@form |== formTag( ... )

你将可以正常Post数据.关于打开跨域访问伪造(CSRF)监测和关于安全的更多信息, 请查看安全章节.

擦除元素

如果你在模版中标记@dummy元素, 它不会在视图中输出.假设你的模版这样写.

<div>
<p>Hello </p>
<p data-tf="@dummy">message ..</p>
</div>

然后, 视图(view)将输出下面的结果

<div>
<p>Hello </p>
</div>

擦除标签

你可以仅保留内容但是删除起始标签和结束标签.
举例, 当使用布局(layout)时, <html>标签会通过布局(laytout)文件输出, 所以你不再需要在模版中输出, 而你希望布局(layout)基于HTML,而同时将<html>标签保留在模版中.
假设你的模版这样写.

<html data-tf="@dummytag">
<p>Hello </p>
</html>

然后, 视图(view)将输出下面的结果

<p>Hello </p>

当你希望在网页设计时保留, 但是在视图中擦除时可以使用它.

包含头文件

我们已经说过关于界面逻辑模版转换到C++代码.头文件和用户定义的文件不会自动包含, 必须自己添加它们.然而, 基本的Treefrog头文件会被包含.举例, 如果你希望包含user.hblog.h文件, 你应该在界面逻辑的顶部这样写:

#include "blog.h"
#include "user.h"

所有的都和C++代码一样!
以#include开头的字符串自己转移到视图(view)的代码中.

Otama操作符

下面的表描述了我们已经讨论过的Otama操作符.

操作符Operator描述Description说明Remarks
:元素替换
被标记的元素和子元素会完全被操作符右侧的eh()方法或者echo()方法输出的内容替换.
%%表示元素本身可以被替换
~内容替换
被标记的元素的内容会被操作符右侧的eh()方法或者echo()方法输出的内容替换.
 
+属性增加
如果想更已经标记的元素增加一个属性, 使用这个操作符加上操作符右侧的echo()方法输出的一个字符串.
+= 是HTML转义,可能用得不多.
|==元素合并
Based on the marked elements, the specified strings will be merged on the right-hand side of this operator.
’|’ 和’|=’ 不可以使用.


这4个操作符的扩展版本在下面.不再需要echo()语句和eh()语句后, 代码能够写得更短.

操作符Operator描述 Description
:=
:==
:=$
:==$
元素被HTML转义的变量替换.
元素被变量替换.
元素被HTML转义的导出的对象替换.
元素被导出的对象替换.
~=
~==
~=$
~==$
用HTML转义的变量替换内容.
用变量替换内容.
用HTML转义的导出对象替换内容.
用导出的对象替换内容.
+=
+==
+=$
+==$
增加一个HTML转义的变量到属性.
增加一个变量到属性.
增加一个HTML转义的导出对象到属性.
增加一个导出的对象到属性.
|==$用导出的对象合并元素.


注释

如果你希望在界面逻辑中写注释, 请将注释写在//中.

@foo ~= bar    /*  这里是注释 */

说明: C++ 使用”// ..” 但是这个不能用在界面逻辑中.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值