HTML 模板渲染
一、全部模板放在一个目录里面的配置方法
1、目录结构
2、首先在项目根目录新建 templates 文件夹,然后在文件夹中新建 对应的index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>这是一个 html 模板</h1>
<h3>{{.title}}</h3>
</body>
</html>
3、单个目录模板代码案例
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
//初始化路由
r := gin.Default()
//加载templates中所有模板文件,注意:一定要在使用模板之前加载
r.LoadHTMLGlob("templates/*")
//r.LoadHTMLFiles("templates/xxx.html", "templates/xxx.html")
//http: //127.0.0.1:8080
r.GET("/", func(c *gin.Context) {
c.HTML(http.StatusOK, "index.html", gin.H{
"title": "index页面-前台页面",
})
})
//http://127.0.0.1:8080/index
r.GET("/index", func(c *gin.Context) {
c.HTML(http.StatusOK, "index.html", map[string]interface{}{
"title": "index页面-前台页面",
})
})
r.Run(":8080")
}
二、模板放在不同目录里面的配置方法
1、目录结构
2、在不同目录下创建同名字的html文件
注意:定义模板的时候需要通过 define 定义名称
admin/index.html
<!-- 相当于给模板定义一个名字 define end 成对出现-->
{{ define "admin/index.html" }}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>后台模板</h1>
<h3>{{.title}}</h3>
</body>
</html>
{{ end }}
default/index.html
<!-- 相当于给模板定义一个名字 define end 成对出现-->
{{ define "default/index.html" }}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>前台模板</h1>
<h3>{{.title}}</h3>
</body>
</html>
{{end}}
3、单个目录模板代码案例
package main
import (
"github.com/gin-gonic/gin"
"net/http"
"os"
"path/filepath"
"strings"
)
func main() {
// 加载引擎
router := gin.Default()
//方法一
// 加载模板
// 如果模板在多级目录里面的话需要这样配置 r.LoadHTMLGlob("templates/**/**/*") /**表示目录
//router.LoadHTMLGlob("templates/**/*")
//方法二
//加载templates中所有模板文件, 使用不同目录下名称相同的模板,注意:一定要放在配置路由之前才得行
//如果模板在多级目录里面的话需要这样配置 r.LoadHTMLGlob("templates/**/**/*") /** 表示目录
//LoadHTMLGlob只能加载同一层级的文件
//比如说使用router.LoadHTMLFile("/templates/**/*"),就只能加载/templates/admin/或者/templates/order/下面的文件
//解决办法就是通过filepath.Walk来搜索/templates下的以.html结尾的文件,把这些html文件都加载一个数组中,然后用LoadHTMLFiles加载
//r.LoadHTMLGlob("templates/**/*")
var files []string
filepath.Walk("./templates", func(path string, info os.FileInfo, err error) error {
if strings.HasSuffix(path, ".html") {
files = append(files, path)
}
return nil
})
router.LoadHTMLFiles(files...)
// http://127.0.0.1:8080/default
router.GET("/default", func(c *gin.Context) {
c.HTML(http.StatusOK, "default/index.html", gin.H{
"title": "前台首页",
})
})
// http://127.0.0.1:8080/admin
router.GET("/admin", func(c *gin.Context) {
c.HTML(http.StatusOK, "admin/index.html", gin.H{
"title": "后台首页",
})
})
router.Run(":8080")
}
三、静态文件及模板
1、代码结构
2、完整代码
admin/index.html
<!-- 相当于给模板定义一个名字, define end 必须成对出现 -->
{{ define "admin/index.html" }}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>后台首页</title>
</head>
<body>
<h2>{{.title}}</h2>
</body>
</html>
{{ end }}
admin/news.html
{{ define "admin/news.html" }}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>后台新闻详情</title>
</head>
<body>
<h2>{{.title}}</h2>
<h3>{{.news.Title}}</h3>
<h4>{{.news.Content}}</h4>
</body>
</html>
{{ end }}
default/index.html
<!-- 相当于给模板定义一个名字, define end 必须成对出现 -->
{{ define "default/index.html" }}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/static/css/base.css">
<title>这是一个简单的页面</title>
</head>
<body>
{{ template "public/page_header.html" .}}
<h2>{{.title}}</h2>
<img src="/static/images/header.jpg">
<!-- 定义变量 把后台的变量赋值给$t -->
{{ $t := .title}}
<!-- 显示$t -->
<h4> {{ $t }}</h4>
<!-- if判断 -->
{{if gt .score 90}}
<div>优秀</div>
<br/>
{{else if gt .score 80}}
<div>良好</div>
<br/>
{{else if gt .score 70}}
<div>可以</div>
<br/>
{{ else }}
<div>合格</div>
<br/>
{{end}}
<!-- 循环数据 -->
<ul>
<!-- 循环切片 -->
{{range $k, $v := .hobby}}
<li>{{$k}} => {{$v}}</li>
{{end}}
</ul>
<ul>
<!-- 循环结构体 -->
{{range $k, $v := .newList}}
<li>{{$k}} => {{$v.Title}} --- {{$v.Content}}</li>
{{end}}
</ul>
<ul>
<!-- 循环空数组/切片 判断 -->
{{range $k, $v := .testSlice}}
<li>{{$k}} => {{$v.Title}} --- {{$v.Content}}</li>
{{else}}
<li>空数据</li>
{{end}}
</ul>
<ul>
<!-- with 解析结构体-->
{{with .news}}
<li>{{.Title}} => {{.Content}}</li>
{{end}}
</ul>
<h4>
<!--预定义函数 -->
{{.title}}的长度为{{len .title}}
</h4>
<h4>
<!--自定义函数 -->
{{UnixToTime .date}}
<br>
{{Println .title "--------------"}}
<br>
{{Println "~~~~~~~~~~~" .news.Title}}
<br>
{{Println .title .news.Title}}
</h4>
<!-- 嵌套 template -->
{{ template "public/page_footer.html" .}}
</body>
</html>
{{end}}
default/news.html
<!-- 相当于给模板定义一个名字, define end 必须成对出现 -->
{{ define "default/news.html" }}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>news</title>
</head>
<body>
{{ template "public/page_header.html" .}}
<link rel="stylesheet" href="static/css/base.css">
<h2>{{.title}}</h2>
<h4>
{{.news.Title}}
<br>
{{.news.Content}}
</h4>
{{ template "public/page_footer.html" .}}
</body>
</html>
{{ end }}
public/page_header.html
<!-- 相当于给模板定义一个名字, define end 必须成对出现 -->
{{ define "public/page_header.html" }}
<h1>
公共的 --- {{.title}}
</h1>
{{end}}
public/page_footer.html
<!-- 相当于给模板定义一个名字, define end 必须成对出现 -->
{{ define "public/page_footer.html" }}
<h4>
公共的底部
</h4>
{{end}}
go代码
package main
import (
"github.com/gin-gonic/gin"
"html/template"
"net/http"
"time"
)
type Article struct {
Title string `json:"title"`
Content string `json:"
"`
}
// UnixToTime 时间戳转换成日期函数
func UnixToTime(timestamp int) string {
t := time.Unix(int64(timestamp), 0)
return t.Format("2006-01-02 15:04:05")
}
func Println(str1 string, str2 string) string {
return str1 + str2
}
func main() {
//初始化路由
r := gin.Default()
//自定义模板函数,必须在r.LoadHTMLGlob前面
r.SetFuncMap(template.FuncMap{
"UnixToTime": UnixToTime, //注册模板函数
"Println": Println,
})
//加载templates中所有模板文件, 使用不同目录下名称相同的模板,注意:一定要放在配置路由之前才得行
r.LoadHTMLGlob("templates/**/*")
//配置静态web目录 第一个参数表示路由,第二个参数表示映射的目录
r.Static("/static", "./static")
//配置路由
//前台路由
r.GET("/", func(c *gin.Context) {
//渲染模板文件
c.HTML(http.StatusOK, "default/index.html", gin.H{
"title": "这是一个简单的页面",
"score": 88,
"hobby": []string{"吃饭", "睡觉", "打豆豆"}, // 切片
"newList": []interface{}{ // 接口
&Article{
Title: "新闻标题1",
Content: "新闻内容1",
},
&Article{
Title: "新闻标题2",
Content: "新闻内容2",
},
},
"testSlice": []string{}, // 空数组/空切片
"news": &Article{ // 结构体
Title: "新闻标题3",
Content: "新闻内容3",
},
"date": 1714115969,
})
})
r.GET("/news", func(c *gin.Context) {
news := &Article{
Title: "新闻标题",
Content: "新闻内容",
}
c.HTML(http.StatusOK, "default/news.html", gin.H{
"title": "新闻详情",
"news": news,
})
})
//后台路由
r.GET("/admin", func(c *gin.Context) {
//渲染模板文件
c.HTML(http.StatusOK, "admin/index.html", gin.H{
"title": "后台首页",
})
})
r.GET("/admin/news", func(c *gin.Context) {
news := &Article{
Title: "后台新闻标题",
Content: "后台新闻内容",
}
c.HTML(http.StatusOK, "admin/news.html", gin.H{
"title": "后台新闻详情",
"news": news,
})
})
r.Run() // 启动一个web服务
}