首页 前端知识 gin框架 HTML 模板加载,渲染 使用详解和总结

gin框架 HTML 模板加载,渲染 使用详解和总结

2024-08-27 09:08:58 前端知识 前端哥 822 389 我要收藏

gin框架中默认的HTML模板渲染使用  LoadHTMLGlob() 或者 LoadHTMLFiles() , 这个地方如果是使用的LoadHTMLGlob() 这个方法的话是有坑的,即当你的模板文件放在不同的文件夹中时,使用这个方式加载会将文件夹也作为文件加载进去,从而直接在模板渲染的时候抛异常!! 

假设在我们的项目templates文件夹中有如下结构的模板文件:

├── article
│   ├── detail.html
│   └── index.html
├── footer.html
├── header.html
├── index.html
└── search
    ├── detail.html
    └── index.html

r := gin.Default()

LoadHTMLGlob模板加载匹配模式

 r.LoadHTMLGlob("templates/*.html")    如果是这种模式就只能加载顶层的3个html文件,子目录中的文件无法加载

 r.LoadHTMLGlob("templates/**/*.html")   这种方式就只能加载子目录article, search中一共4个文件

r.LoadHTMLGlob("template/**/*")  这种模式 只能加载子目录中的所有文件或者文件夹,顶层的3个模板无法加载

r.LoadHTMLGlob("template/**")  这种模式 可以加载所有的文件和目录(坑,模板编译时直接报异常, 不能使用这种方式!)

上面的4种方式加载模板对于我们上面的模板结构都不可用,直接抛弃! 

上面的方式只能适用于没有子目录的模板加载

filepath.WalkDir  + LoadHTMLFiles() 的方式加载模板

对于我们上面的模板结构只能采用LoadHTMLFiles()方式加载了, 使用这个方式加载,我们需要先自己加载我们需要的模板文件, 这个就需要使用filepath.WalkDir 这个目录遍历大杀器出场了。废话补多少直接删代码:

// 模板文件加载
	var tplFiles []string
	filepath.WalkDir("templates", func(path string, d fs.DirEntry, err error) error {
		if !d.IsDir() && strings.HasSuffix(d.Name(), ".html") {
			// 非目录,且是.html结尾的文件加入到模板文件列表
			tplFiles = append(tplFiles, path)
		}
		return nil
	})

	r.LoadHTMLFiles(tplFiles...) // 加载html模板

 在gin控制器中通过.HTML方法使用模板

这个非常简单直接用HTML方法即可。 需要注意的是这里的模板名称是很讲究的,我们来看一下这个HTML方法的原型: func (c *gin.Context) HTML(code int, name string, obj any)   

这里第一个参数是http的状态码一般都是200即可, 第二个参数name 就是我们要渲染的模板的名称,这里的名称默认是你加载的文件的不区分目录的文件名, 由于默认不区分目录,所以如果你有多个同名的文件,则必须在对应的文件中使用 define对文件名进行定义,如: {{ define "index.html"}}   你的模板内容  {{end}}   。  如果你加载的文件名每个都是唯一的,则不需要定义也可以直接使用。


r.GET("/index", func(c *gin.Context) {
    // 注意这里的第二个参数 模板名是很有讲究的
    c.HTML(http.StatusOK, "index.html", gin.H{
        "title": "Main website",
    })
})
r.Run(":8080")

html模板文件示例和模板包含命名定义使用示例

index.html 示例:

注意,由于index.html文件名称有重复,所以这里我们必须使用define对文件名进行定义,否则index.html加载的就可能不是你期望的文件!!!

另外这里我们使用内置函数 template 对另外2个公共的模板文件进行加载。 {{template "xxx.html" .}}

{{define "index.html"}}
<!DOCTYPE html>
<html>
  <head>
    {{template "header.html" .}}
  </head>

  <body>
    <div class="container-fluid">
      <H1>Hello Gin HTML</H1>
      <!--- footer --->
      {{template "footer.html" .}}
    </div>
  </body>
</html>
{{end}}

head.html

这个head.html文件名是唯一的,所以不需要是哟共define定义也可使用, 注意这里的标题 {{.title}} 这个直接使用了 c.HTML方法的第三个参数中传递的动态变量

<meta charset="utf-8" />
<meta
  name="viewport"
  content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<title>{{.title}}</title>

footer.html

<!--- footer --->
<footer style="height: 100px; background: #1b1c1d">
  <div style="text-align: center; font-size: 14px; padding-top: 50px">
    By
    <a href="http://dev.tekin.cn" target="_blank"
      >{{.title}}</a>
  </div>
</footer>

article/index.html文件内容

注意这里的define定义的文件名 {{ define "article/index.html"}}   我们一般以当前文件所在的模板文件夹下的相对路径来命名。 在c.HTML里面使用的时候我们就使用 c.HTML(200, "article/index.html", nil) 即可。

{{ define "article/index.html"}}
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Article index</title>
    <link rel="stylesheet" href="">
</head>
<body>
    <h1>Hello my article</h1>
</body>
</html>

{{end}}

自定义模板渲染器

你可以使用自定义的 html 模板渲染

import "html/template"

func main() {
	router := gin.Default()
	html := template.Must(template.ParseFiles("file1", "file2"))
	router.SetHTMLTemplate(html)
	router.Run(":8080")
}

自定义分隔符

r.Delims("{[{", "}]}") // 自定义模板分隔符 这个一般情况下我们保持默认即可

自定义模板功能

这个就是使用.SetFuncMap加载我们自定义的函数进去就可以。 推荐在c.HTML里面绑定对象的方式调用对象方法更方便,调用方式为 将函数名换为   对象名.方法名

import (
    "fmt"
    "html/template"
    "net/http"
    "time"

    "github.com/gin-gonic/gin"
)

func formatAsDate(t time.Time) string {
    year, month, day := t.Date()
    return fmt.Sprintf("%d/d/d", year, month, day)
}

func main() {
    router := gin.Default()
    router.Delims("{[{", "}]}")
    router.SetFuncMap(template.FuncMap{
        "formatAsDate": formatAsDate,
    })
    router.LoadHTMLFiles("templates/index.html")

    router.GET("/raw", func(c *gin.Context) {
        c.HTML(http.StatusOK, "raw.tmpl", map[string]interface{}{
            "now": time.Date(2017, 07, 01, 0, 0, 0, 0, time.UTC),
        })
    })

    router.Run(":8080")
}

在模板中使用我们自定义的函数:

Date: {[{.now | formatAsDate}]}   这个是使用管道符 | 方式,

也可以这样使用  Date: {[{formatAsDate  .now }]}  如果是多个参数用空格分开即可。

 附录 go内置的默认模板函数

func builtins() FuncMap {
	return FuncMap{
		"and":      and,
		"call":     call,
		"html":     HTMLEscaper,
		"index":    index,
		"slice":    slice,
		"js":       JSEscaper,
		"len":      length,
		"not":      not,
		"or":       or,
		"print":    fmt.Sprint,
		"printf":   fmt.Sprintf,
		"println":  fmt.Sprintln,
		"urlquery": URLQueryEscaper,

		// Comparisons
		"eq": eq, // ==
		"ge": ge, // >=
		"gt": gt, // >
		"le": le, // <=
		"lt": lt, // <
		"ne": ne, // !=
	}
}

gin框架HTML渲染使用总结:

1. gin框架中渲染模板必须要先加载,如果模板文件中没有子目录可以使用 LoadHTMLGlob() ,如果有子目录推荐使用 filepath.WalkDir  + LoadHTMLFiles() 的方式加载模板;

2. 模板名称默认为加载的文件的忽略目录的文件名, 如果有多个同名文件,则默认使用功能的是第一个加载的模板文件;

3. 在模板中包含其他模板可以使用template函数进行加载包含,即 {{template "xxx.html" .}}

4. gin中模板渲染使用c.HTML方法,这个方法有3个参数,第一个是http状态码,第二个是模板名称,第三个是要传递给模板的变量数据, 这个我们一般使用map数据结构

5. 自定义模板函数实际上就是将自己定义的函数使用 r.SetFuncMap(template.FuncMap{ "模板中使用的函数名": 函数名,})

6. 一般情况下我们可以通过在c.HTML的第三个参数里面绑定一个对象来代替自定义函数, 直接在模板中调用对象的方法更加方便和简洁,不需要另外绑定函数即可使用。

转载请注明出处或者链接地址:https://www.qianduange.cn//article/16959.html
标签
gingolang
评论
会员中心 联系我 留言建议 回顶部
复制成功!