Go 视图模板篇(三):参数、管道和函数调用


参数

参数可以看做模板中的变量,参数值可以是布尔值、整型、字符串、还可以是结构体、结构体的字段、或者数组的索引。

我们可以这样设置参数值:

$variable := value

乍看起来没啥用,用在指令中则可以大放异彩:

{{ range $key, $value := . }} 
    The key is {{ $key }} and the value is {{ $value }} 
{{ end }}

管道

管道是链接起来的参数、函数或者方法序列,和 Unix 管道一样:

{{ p1 | p2 | p3 }}

管道允许我们将上一个输出作为参数传递到下一个,不同元素之间通过 | 分隔。

服务端处理器示例代码:

package main
    
import (
    "html/template"
    "net/http"
)
    
func pipelineExample(w http.ResponseWriter, r *http.Request)  {
    t := template.Must(template.ParseFiles("pipeline.html"))
    t.Execute(w, 12.3456)
}
    
func main()  {
    http.HandleFunc("/pipeline", pipelineExample)
    http.ListenAndServe(":8080", nil)
}

对应的模板文件 pipeline.html 代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Pipeline Demo</title>
</head>
<body>
    {{ . | printf "%.2f" }}
</body>
</html>

上述管道代码会将传入视图模板的变量作为 printf 函数的参数,通过 %.2f 格式打印出来:

-w614

printf 函数封装了 fmt.Sprintf 方法,是 Go 模板引擎内置的函数,如果是自定义函数的话,需要通过指定语法将其绑定到模板引擎,否则系统不能识别,下面我们就来看看如何在 Go 视图模板中通过管道调用自定义函数。

自定义函数

Go 模板引擎内置了丰富的基础函数,其中有很多是 fmt.Sprint 的变体,比如前面示例中使用的 printf。此外,还支持开发者自定义的函数。

要自定义函数,需要这么做:

  • 创建 FuncMap 字典,然后将函数名作为键,将函数体作为值。
  • FuncMap 应用到模板引擎。

下面我们来看一个示例,这个示例中,我们通过自定义函数设置日期输出格式。

编写服务端处理器示例代码如下:

package main
    
import (
    "html/template"
    "net/http"
    "time"
)
    
func formatDate(t time.Time) string {
    layout := "2006-01-02 15:04:05"
    return t.Format(layout)
}
    
func customFunctionExample(w http.ResponseWriter, r *http.Request)  {
    funcMap := template.FuncMap{
        "fdate": formatDate,
    }
    t := template.New("function.html").Funcs(funcMap)
    t, _ = t.ParseFiles("function.html")
    t.Execute(w, time.Now())
}
    
func main()  {
    http.HandleFunc("/date_format", customFunctionExample)
    http.ListenAndServe(":8080", nil)
}

可以看到,我们通过模板引擎提供的 FuncMap 方法将自定义的 formatDate 函数注册到 fdate 键,然后将返回的 funcMap 通过 Funcs 方法注入到视图模板中,这样,在对应的视图模板中就可以调用 funcMap 中注册的自定义函数了。

对应的模板文件 function.html 代码如下,我们在里面通过管道的方式调用了 fdate 函数:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Custom Function</title>
</head>
<body>
    <div> The date/time is {{ . | fdate }} </div>
</body>
</html>

这里需要注意的是,我们必须在解析模板之前应用自定义函数到模板引擎(前后顺序不能颠倒):

t := template.New("function.html").Funcs(funcMap)
t, _ = t.ParseFiles("function.html")

这是因为在解析模板时需要确定模板中使用的函数。另外,当我们通过 New 方法创建模板时,需要手动设置模板名(之前都是自动将文件名作为模板名),然后在模板上调用 ParseFiles 时再次传递的实际上是待解析的模板文件,而不是模板名,这里需要区分下。

运行服务端代码启动服务器,在浏览器中访问 http://localhost:8080/date_format,输出结果如下,表明自定义日期格式函数调用成功:

-w668

除了管道之外,还可以在指令中使用自定义的函数,这个时候可以将 . 作为参数传递过来:

<html> 
    <head> 
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 
        <title>Go Web Programming</title> 
    </head> 
    <body> 
        <div>The date/time is {{ fdate . }}</div> 
    </body> 
</html>

两种方式实现的效果一样,但可以看出,管道的方式更加直观和灵活,我们还可以在后面继续追加其他函数对结果进行处理(链式调用)。


Vote Vote Cancel Collect Collect Cancel

<< 上一篇: Go 视图模板篇(二):通过指令实现控制结构和模板引入

>> 下一篇: Go 视图模板篇(四):上下文感知与 XSS 攻击