Go --- html/template模板包的使用(二)

简介: Go --- html/template模板包的使用

自定义函数

若是觉得模板中的预定义函数不够用,这时候就需要定义自己的函数了。

我们一般不在模板中定义自己的函数,而是在渲染模板之前给定自己所定义的函数,这将使用了Fancs方法。

scold := func(a string)  string {
    return a + "TNND"
  }
// 这个New就是用给的这个名字重新分配一个模板
// 调用Funcs方法前要先调用New方法
  t, err := template.New("test").Funcs(template.FuncMap{"scold" : scold}).Parse

Funcs方法:

// 可以看出,在Funcs中要传入一个 map[string]interface{} ,
// 其中是string代表的自定义的方法在模板中叫啥名
// 第二个空接口穿的应该是自定义的函数
func (t *Template) Funcs(funcMap FuncMap) *Template {
  t.text.Funcs(template.FuncMap(funcMap))
  return t
}
type FuncMap map[string]interface{}

在模板中使用自定义函数时,要用到管道的方法

{{ a | b }}
这种写法的意思是将 a 的输出通过管道再作为 b 的输入,最后呈现出来的是 b 的输出

例子:

test.tmpl

{{ define "test" }}
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <title>自定义函数</title>
</head>
<body>
    {{/*
       {{ a | b }}
       这种写法的意思是将 a 的输出通过管道再作为 b 的输入,最后呈现出来的是 b 的输出
     */}}
    {{ . | scold }}
</body>
</html>
{{end}}

main.go

package main
import (
  "fmt"
  "html/template"
  "net/http"
)
func sayHello(w http.ResponseWriter,r *http.Request)  {
  scold := func(a string)  string {
    return a + "TNND"
  }
  t, err := template.New("test").Funcs(template.FuncMap{"scold" : scold}).ParseFiles("./test.tmpl")
  if err != nil {
    fmt.Printf("parse file failed err := %v",err)
  }
  err = t.Execute(w, "为什么不喝,")
  if err != nil {
    fmt.Printf("execute file failed err := %v",err)
  }
}
func main() {
  http.HandleFunc("/",sayHello)
  err := http.ListenAndServe(":9000", nil)
  if err != nil {
    fmt.Printf("listen address failed err = %v",err)
  }
}

嵌套

就是在一个模板中嵌套另外的一个模板。

需要使用的语法为

在需要嵌套的地方
{{ template 模板名 . }}
其中,这个 . 是在模板中传递数据用的

例子:

test.tmpl

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <title>嵌套</title>
</head>
<body>
    ul :<br>
    {{ template "ul.tmpl" . }}
    <hr>
    ol :<br>
    {{ template "ol.tmpl" . }}
</body>
</html>

ol.tmpl

<ol>
    <li>{{ .name }}</li>
    <li>{{ .sex }}</li>
</ol>

ul.tmpl

<ul>
    <li>{{ .name }}</li>
    <li>{{ .sex }}</li>
</ul>

main.go

package main
import (
  "fmt"
  "html/template"
  "net/http"
)
func nest(w http.ResponseWriter,r *http.Request)  {
  // 不能写成template.ParseFiles("./ul.tmpl","./test.tmpl","./ol.tmpl")
  // 因为是test.tmpl是主模板,ul.tmpl和ol.tmpl需要等主模板解析完之后在解析
  t, err := template.ParseFiles("./test.tmpl","./ul.tmpl","./ol.tmpl")
  if err != nil {
    fmt.Printf("parse file failed err := %v",err)
  }
  mp := map[string]interface{}{
    "name": "张大炮",
    "sex": "女",
  }
  err = t.Execute(w, mp)
  if err != nil {
    fmt.Printf("execute file failed err := %v",err)
  }
}
func main() {
  http.HandleFunc("/",nest)
  err := http.ListenAndServe(":9000", nil)
  if err != nil {
    fmt.Printf("listen address failed err = %v",err)
  }
}

填空 block

相当于继承,一个网页项目会有一些公共的页面信息,为了不每个页面都将这些信息写上一边,就要有根模板,这时候其他的页面就需要继承根模板。

使用block

将数据传递给该模板名的模板
{{ block 模板名 数据}}
{{ end }}

在使用时一定要引入根模板

用 . 来接受根模板传来的所有数据
{{ template 跟模板名 .}}

例子:

test.tmpl

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <title>填空</title>
</head>
<body>
    <div>
        <p style="text-align: center">
            {{ block "content" .}}
            {{ end }}
        </p>
    </div>
</body>
</html>

content.tmpl

{{ template "test.tmpl" .}}
{{/*
一个项目里面肯定要有好些个功能,如果每一个功能都有一些相同作用的文件,
这样就很难保证这些文件不会出现重复的问题,
有两个解决方案,
1. 在每一个模板上方定义一个名字
2. 创建一个包,包里分层放,不同层代表着不同的功能 然后使用template.ParseGlob() 正则解析
*/}}
{{ define "content" }}
    {{ . }}
{{end}}

main.go

package main
import (
  "fmt"
  "html/template"
  "net/http"
)
func sayHello(w http.ResponseWriter,r *http.Request)  {
  t, err := template.ParseFiles("./test.tmpl","./content.tmpl")
  if err != nil {
    fmt.Printf("parse file failed err := %v",err)
  }
  err = t.ExecuteTemplate(w,"content", "这都是大棚的瓜")
  if err != nil {
    fmt.Printf("execute file failed err := %v",err)
  }
}
func main() {
  http.HandleFunc("/",sayHello)
  err := http.ListenAndServe(":9000", nil)
  if err != nil {
    fmt.Printf("listen address failed err = %v",err)
  }
}

安全测试

就像开头所说,html/template这个包传递给的模板的数据会进行安全处理。

测试:

test.tmpl

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <title>安全测试</title>
</head>
<body>
{{/*并不会出现执行标签的现象*/}}
    弹窗:{{ .msg }}<br>
    链接1:{{ .a }}<br>
    链接2:{{ .a | trust }}<br>
</body>
</html>

main.go

package main
import (
  "fmt"
  "html/template"
  "net/http"
)
func sayHello(w http.ResponseWriter,r *http.Request)  {
  t, err := template.New("test.tmpl").Funcs(template.FuncMap{
    "trust": func(s string) template.HTML {
      return template.HTML(s)
    },
  }).ParseFiles("./test.tmpl")
  if err != nil {
    fmt.Printf("parse file failed err := %v",err)
  }
  m := map[string]interface{}{
    "msg":"<script>alert('张三撺掇着李四去王五家打了赵六')</script>",
    "a": "<a href='https://blog.csdn.net/weixin_52025712'>本人博客</a>",
  }
  err = t.Execute(w, m)
  if err != nil {
    fmt.Printf("execute file failed err := %v",err)
  }
}
func main() {
  http.HandleFunc("/",sayHello)
  err := http.ListenAndServe(":9000", nil)
  if err != nil {
    fmt.Printf("listen address failed err = %v",err)
  }
}

修改默认标识符

模板中默认标识符 {{ }} 可能会与其他语言中的表示符冲突,这时候我们就要重新定义默认标识符,需要使用Delims方法

// 修改默认标识符为 [ ]
t, err := template.New("test.tmpl").Delims("[","]").ParseFiles("./test.tmpl")

Delims:

// left和rigth分别代表标识符左右两个部分
func (t *Template) Delims(left, right string) *Template {
  t.text.Delims(left, right)
  return t
}

例子:

test.tmpl

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <title>修改默认标识符</title>
</head>
<body>
    [ . ]
</body>
</html>

main.go

package main
import (
  "fmt"
  "html/template"
  "net/http"
)
func sayHello(w http.ResponseWriter,r *http.Request)  {
  t, err := template.New("test.tmpl").Delims("[","]").ParseFiles("./test.tmpl")
  if err != nil {
    fmt.Printf("parse file failed err := %v",err)
  }
  err = t.Execute(w, "hello")
  if err != nil {
    fmt.Printf("execute file failed err := %v",err)
  }
}
func main() {
  http.HandleFunc("/",sayHello)
  err := http.ListenAndServe(":9000", nil)
  if err != nil {
    fmt.Printf("listen address failed err = %v",err)
  }
}

一个简单的表单传值的例子

get.tmpl

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <title>表单传值</title>
</head>
<body>
    <form action="/" method="post">
        <label>
            <input type="text" name="name">
        </label><br>
        <label>
            <input type="text" name="age">
        </label><br>
        <label>
            <input type="radio" name="sex" value="男">
        </label> 男<br>
        <label>
            <input type="radio" name="sex" value="女">
        </label> 女<br>
    <button type="submit">提交</button>
</form>
</body>
</html>

post.tmpl

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <title>接受表单传过来的值</title>
</head>
<body>
    姓名:{{ .name }}<br>
    性别:{{ .sex }}<br>
    年龄:{{ .age }}
</body>
</html>

main.go

package main
import (
  "fmt"
  "html/template"
  "net/http"
)
func form(w http.ResponseWriter,r *http.Request)  {
  switch r.Method {
  case "GET":
    t, err := template.ParseFiles("./get.tmpl")
    if err != nil {
      fmt.Printf("parse file failed err := %v",err)
    }
    err = t.Execute(w, nil)
    if err != nil {
      fmt.Printf("execute file failed err := %v",err)
    }
  case "POST":
    t, err := template.ParseFiles("./post.tmpl")
    if err != nil {
      fmt.Printf("parse file failed err := %v",err)
    }
    name := r.FormValue("name")
    //fmt.Printf("name = %s\n",name)
    sex := r.FormValue("sex")
    //fmt.Printf("sex = %s\n",sex)
    age := r.FormValue("age")
    //fmt.Printf("age = %s\n",age)
    m := map[string]interface{}{
      "name":name,
      "sex":sex,
      "age":age,
    }
    err = t.Execute(w, m)
    if err != nil {
      fmt.Printf("execute file failed err := %v",err)
    }
  }
}
func main() {
  // 配置路由
  http.HandleFunc("/",form)
  // 启动
  err := http.ListenAndServe(":9000", nil)
  if err != nil {
    fmt.Printf("listen address failed err = %v",err)
  }
}

参考文章:

  1. 李文周的博客
  2. xyz098的简书

希望大家能多去支持一下上面的两位大佬

最后再向大家推荐一首今天在单曲循环的歌遇见 西安话版 吴昊晨

相关文章
|
5天前
|
Linux Go iOS开发
怎么禁用 vscode 中点击 go 包名时自动打开浏览器跳转到 pkg.go.dev
本文介绍了如何在 VSCode 中禁用点击 Go 包名时自动打开浏览器跳转到 pkg.go.dev 的功能。通过将 gopls 的 `ui.navigation.importShortcut` 设置为 &quot;Definition&quot;,可以实现仅跳转到定义处而不打开链接。具体操作步骤包括:打开设置、搜索 gopls、编辑 settings.json 文件并保存更改,最后重启 VSCode 使设置生效。
25 7
怎么禁用 vscode 中点击 go 包名时自动打开浏览器跳转到 pkg.go.dev
|
4月前
|
存储 Go
如何使用 templ 在 Go 中编写 HTML 用户界面?
如何使用 templ 在 Go 中编写 HTML 用户界面?
|
4月前
|
自然语言处理 搜索推荐 Go
goctl 技术系列 - Go 模板入门
goctl 技术系列 - Go 模板入门
|
20天前
|
Go 索引
go语言使用strings包
go语言使用strings包
23 3
|
1月前
|
定位技术
时尚的联系我们表单HTML模板(源码)
一款时尚的联系我们表单Html模板,带地图和所在位置,输入基本信息和信息发送,看起来很漂亮的联系我们页面。
48 1
时尚的联系我们表单HTML模板(源码)
|
1月前
|
编译器 Go 开发者
go语言中导入相关包
【11月更文挑战第1天】
30 3
|
2月前
|
存储 Go 数据库
Go语言Context包源码学习
【10月更文挑战第21天】Go 语言中的 `context` 包用于在函数调用链中传递请求上下文信息,支持请求的取消、超时和截止时间管理。其核心接口 `Context` 定义了 `Deadline`、`Done`、`Err` 和 `Value` 方法,分别用于处理截止时间、取消信号、错误信息和键值对数据。包内提供了 `emptyCtx`、`cancelCtx`、`timerCtx` 和 `valueCtx` 四种实现类型,满足不同场景需求。示例代码展示了如何使用带有超时功能的上下文进行任务管理和取消。
|
4月前
|
缓存 Java 应用服务中间件
SpringMVC入门到实战------七、SpringMVC创建JSP页面的详细过程+配置模板+实现页面跳转+配置Tomcat。JSP和HTML配置模板的差异对比(二)
这篇文章详细介绍了在SpringMVC中创建JSP页面的全过程,包括项目的创建、配置、Tomcat的设置,以及如何实现页面跳转和配置模板解析器,最后还对比了JSP和HTML模板解析的差异。
SpringMVC入门到实战------七、SpringMVC创建JSP页面的详细过程+配置模板+实现页面跳转+配置Tomcat。JSP和HTML配置模板的差异对比(二)
|
3月前
|
存储 Go
Golang语言基于go module方式管理包(package)
这篇文章详细介绍了Golang语言中基于go module方式管理包(package)的方法,包括Go Modules的发展历史、go module的介绍、常用命令和操作步骤,并通过代码示例展示了如何初始化项目、引入第三方包、组织代码结构以及运行测试。
65 3
|
4月前
|
编译器 数据库连接 Go
Go Sync 包:并发的 6 个关键概念
Go Sync 包:并发的 6 个关键概念