实现在go语言的模板中使用include
现在的go语言中,在使用模板的时候无法使用include
来包含其它模板文件。这就导致有时候想include
一些诸如header.html
、footer.html
的需求很麻烦。本文的目标就是在go自带的模板库上实现这个功能。
首先创建一个go工程,包含以下几个文件:
.
├── go.mod
├── views
│ ├── footer.html
│ └── index.html
└── web.go
我们需要实现的就是在index.html
中include
footer.html
的内容
第一步、实现展示index.html
index.html
的内容
Go Include 测试
这是index.html正文内容
当前时间: {{ .Now }}
接着实现web.go
package main
import (
"fmt"
"html/template"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
t := template.New("index.html")
t, err := t.ParseFiles("views/index.html")
if err != nil {
fmt.Fprintf(w, "err: %v", err)
return
}
data := make(map[string]string)
data["Now"] = time.Now().Format("2006-01-02 03:04:05")
t.ExecuteTemplate(w, "index.html", data)
}
func main() {
m := http.NewServeMux()
m.HandleFunc("/", handler)
http.ListenAndServe(":80", m)
}
稍微封装一下
func rend(w io.Writer, name string, data interface{}) {
t := template.New(name)
t, err := t.ParseFiles(filepath.Join("views/", name))
if err != nil {
fmt.Fprintf(w, "err: %v", err)
return
}
t.ExecuteTemplate(w, name, data)
}
func handler(w http.ResponseWriter, r *http.Request) {
data := make(map[string]string)
data["Now"] = time.Now().Format("2006-01-02 03:04:05")
rend(w, "index.html", data)
}
编译web.go
并运行就可以在浏览器里看到index.html
的内容了
第二步、实现include
功能
我们预想的include
功能是在模板文件里这样使用
{{ include "xxx.hmtl" }}
这就需要用到自定义函数功能
首先修改index.html
的代码
Go Include 测试
这是index.html正文内容
当前时间: {{ .Now }}
{{ include "footer.html" }}
再添加footer.html
的代码
include
逻辑实现如下
func includeHandler(path string) template.HTML {
buf := new(bytes.Buffer)
rend(buf, path, nil)
return template.HTML(buf.String())
}
func rend(w io.Writer, name string, data interface{}) {
funcs := make(template.FuncMap)
funcs["include"] = includeHandler
t := template.New(name).Funcs(funcs)
t, err := t.ParseFiles(filepath.Join("views/", name))
if err != nil {
fmt.Fprintf(w, "err: %v", err)
return
}
t.Funcs(funcs).ExecuteTemplate(w, name, data)
}
再次编译执行,就可以看到footer.html
的内容了。
但是此刻还有一个重要问题,如果我们想在footer.html
里像下面这样访问程序传给index.html
的参数会访问不到。
所以我们要着手解决这个问题
第三步、传递参数
func includeHandler(data interface{}) interface{} {
return func(path string) template.HTML {
buf := new(bytes.Buffer)
rend(buf, path, data)
return template.HTML(buf.String())
}
}
func rend(w io.Writer, name string, data interface{}) {
funcs := make(template.FuncMap)
funcs["include"] = includeHandler(data)
t := template.New(name).Funcs(funcs)
t, err := t.ParseFiles(filepath.Join("views/", name))
if err != nil {
fmt.Fprintf(w, "err: %v", err)
return
}
t.Funcs(funcs).ExecuteTemplate(w, name, data)
}
再次重新编译执行,就可以看到footer.html
也拿到了参数。
这样我们既实现了include
其它模板,也实现了在模板之间传递参数。