模板引擎

一、介绍模板


模板引擎(template)是为了使用户界面业务数据分离而产生的, 其本身并不是一种深奥的技术.

模板引擎首先会将合法的模板编译为Lua函数, 然后将模板文件和数据通过模板引擎生成一份HTML代码.

admin库真正使用了template来构建服务端渲染页面, 并利用单页面+iframe的模式构建了后台管理系统.

二、基本语法


我们先来了解一下template库的一些基本语法:

  • {{ lua expression }} - lua expression是一段Lua表达式作用为输出的结果, 一些特殊符号会被转义;

  • {* lua expression *} - lua expression是一段Lua表达式作用为输出的结果, 一些特殊符号不会被转义;

  • {% lua code %} - 执行里面的一段lua代码, 如: {% for i = x, y do %} ... {% end %};

  • {(template)} - 导入其它模板文件, 同时支持传参: {(file.html, { message = "Hello, World" })};

  • {-raw-} - 用于包裹一段模板内容, 它将被{-raw-} ... {-raw-}包裹的内容按原样输出(不做任何处理)。

  • {# comments #} - comments内容仅作为注释, 不会包含在输出字符串内. 这段语法的作用类似Lua内的----[[]];

三、转义字符


  • &转义为 &
  • <转义为 &lt;
  • >转义为 &gt;
  • "转义为 &quot;
  • '转义为 &#39;
  • /转义为 &#47;

四、模板API


现在我们来认识几个常用的方法.

1. template.compile


函数原型: template.compile(view, cache_key, plain)

解析、编译和缓存(如果启用了缓存)模板,并将编译后的模板作为将上下文作为参数并将渲染的模板作为字符串返回的函数返回。

cache_key参数决定是否需要缓存模板; plain参数决定将view当成模板解析还是当做模板所在文件路径:

  • 如果plain参数为true的时候, 模板引擎会将其认为是纯字符串模板而不会假设它可能会是一个模板路径;

  • 如果plain参数为false的时候, 模板引擎会将其认为是模板文件路径而不会假设它可能会是一个字符串模板;

    如果plain设置为nil(默认值),则模板不会将文件读取错误视为致命错误,而是返回视图(通常是模板的路径)。

    注意第二个返回值是布尔值. 您可以丢弃它或使用它来确定返回的函数是否已缓存。

2. template.precompile


函数原型: template.precompile(view, path, strip, plain)

将模板预编译为二进制块, 该二进制块可以作为文件写出(您可以将其直接与Lua的loadloadfile一起使用).

cache_key参数决定是否需要缓存模板; strip参数可以使预编译的模板也具有调试信息(默认为true)。

plain参数决定将view当成模板解析还是当做模板所在文件路径:

  • 如果plain参数为true的时候, 模板引擎会将其认为是纯字符串模板而不会假设它可能会是一个模板路径;

  • 如果plain参数为false的时候, 模板引擎会将其认为是模板文件路径而不会假设它可能会是一个字符串模板;

    如果plain设置为nil(默认值),则模板不会将文件读取错误视为致命错误,而是返回视图(通常是模板的路径)。

3. template.caching


函数原型: template.caching(boolean)

此函数用于启用或禁用模板缓存,如果未传递任何参数,则返回模板缓存的当前状态。

默认情况下,启用了模板缓存,但您可能希望在开发或内存不足的情况下禁用它。

五、模板实战


下面我们用2个实例来展示模板引擎的使用方式.

1. 第一个模板


首先, 我们需要优先导入template库. 并且将目前我们熟知的编程语言名称都罗列出来.

  local template = require "template"
  local languages = { 'C', 'C++', 'Java', 'golang', 'Rust', 'Ruby', 'Python', 'perl', 'Lua' }

然后, 我们在当前目录下新建一个view目录, 并在view目录下新建一个名字为base.html的文件。 具体内容如下:

<html>
  <head>
    <title>{*title*}</title>
  </head>
  <body>
    <span><b>{*title*}:</b></span>
    <ul>
      {% if type(languages) == 'table' then %}
        {% for index, lang in ipairs(languages) do %}
          <li>{*index..'. '..lang*}</li>
        {% end %}
      {% end %}
    </ul>
    {# 没错, 注释不会展示给用户看到! #}
  </body>
</html>

然后我们注册一个/languages的页面路由, 并且用它来将我们刚刚完成的模板渲染出来.

local template = require "template"
app:use('/languages', function(content)
  template.cache = {}
  local languages = { 'C', 'C++', 'Java', 'golang', 'Rust', 'Ruby', 'Python', 'perl', 'Lua' }
  return template.compile("view/base.html"){
        title = '语言列表',
    languages = languages
  }
end)

使用template.cache = {}的意思是, 每次都重新刷新缓存去读取文件, 这样方便我们进行调试.

最后打开http://localhost:8080/languages查看效果.

2. 业务升级

当一个项目的业务需求变得非常多的时候, 即是一个单纯的模板页面也会变得非常庞大并且不容维护与阅读.

现在我们来尝试将上面的模板进行模块化, 完成将一个模板分解到多个文件中的动作.

首先, 我们继续在view目录新建head.htmlcontent.html. 然后将这些代码拷贝进去:

{# 这是head.html的内容 #}
<title>{*title*}</title>
{# 这是content.html的内容 #}
<span><b>{*title*}:</b></span>
<ul>
  {% if type(languages) == 'table' then %}
    {% for index, lang in ipairs(languages) do %}
      <li>{*index..'. '..lang*}</li>
    {% end %}
  {% end %}
</ul>
{# 没错, 注释不会展示给用户看到! #}

然后将原来的base.html修改为:

  <html>
    <head>
      {(view/head.html)}
    </head>
    <body>
      {(view/content.html)}
    </body>
  </html>

最后, 由于服务器会自动刷新模板缓存, 我们只需要再次刷新浏览器就能查看效果. {% raw %}

(完整代码示例)

-- main.lua
local httpd = require "httpd"
local app = httpd:new("app")

local template = require "template"
app:use('/languages', function(content)
    local languages = { 'C', 'C++', 'Java', 'golang', 'Rust', 'Ruby', 'Python', 'perl', 'Lua' }
    template.cache = {}
  return template.compile("view/base.html"){
        title = '语言列表',
    languages = languages
  }
end)

app:listen("0.0.0.0", 8080)
app:run()

六、继续学习


本章节我们学会了如何编写HTML模板与使用template引擎, 下一章我们一起学习如何使用数据库与缓存.

Copyright © CandyMi 2019-2022 all right reserved,powered by Gitbook该文件修订时间: 2021-11-19 22:05:46

results matching ""

    No results matching ""