ZYB ARTICLES REPOS

实现在go语言的模板中使用include

现在的go语言中,在使用模板的时候无法使用include来包含其它模板文件。这就导致有时候想include一些诸如header.htmlfooter.html的需求很麻烦。本文的目标就是在go自带的模板库上实现这个功能。

首先创建一个go工程,包含以下几个文件:

.
├── go.mod
├── views
│   ├── footer.html
│   └── index.html
└── web.go

我们需要实现的就是在index.htmlinclude 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的代码


这是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的参数会访问不到。


这是footer.html的内容

当前时间: {{ .Now }}

所以我们要着手解决这个问题

第三步、传递参数

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其它模板,也实现了在模板之间传递参数。