用于统一继承导航栏、页脚等公有部分,通过block、define、template实现模板继承。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.head{height: 50px; background-color: red;width: 100%;text-align: center;}
.main{width: 100%;}
.main .left{width: 30%;height: 1000px;float: left;background-color:violet;text-align: center;}
.main .right{width: 70%;float: left;text-align: center;height: 1000px;background-color:yellowgreen;}
</style>
</head>
<body>
<div class="head">
<h1>head</h1>
</div>
<div class="main">
<div class="left">
<h1>side</h1>
</div>
<div class="right">
{{ block "content" . }}
<h1>content</h1>
{{ end }}
</div>
</div>
</body>
</html>
{{ template "base.tmpl" . }}
{{ define "content" }}
<h5>这是index页面</h5>
{{ . }}
{{ end }}
{{ template "base.tmpl" . }}
{{ define "content" }}
<h5>这是home页面</h5>
{{ . }}
{{ end }}
package main
import (
"html/template"
"net/http"
)
func indexHandleFunc(w http.ResponseWriter, r *http.Request) {
t := template.New("index.tmpl")
t, _ = t.ParseFiles("./base.tmpl", "./index.tmpl")
t.Execute(w, "index")
}
func homeHandleFunc(w http.ResponseWriter, r *http.Request) {
t := template.New("home.tmpl")
t, _ = t.ParseFiles("./base.tmpl", "./home.tmpl")
t.Execute(w, "home")
}
func main() {
server := http.Server{
Addr: "localhost:8080",
}
http.HandleFunc("/index", indexHandleFunc)
http.HandleFunc("/home", homeHandleFunc)
server.ListenAndServe()
}
Go标准库的模板引擎使用的花括号{{和}}作为标识,而许多前端框架(如Vue和 AngularJS)也使用{{和}}作为标识符,所以当同时使用Go语言模板引擎和以上前端框架时就会出现冲突,需要修改标识符,修改前端的或者修改Go语言的。这里演示如何修改Go语言模板引擎默认的标识符:
template.New("test").Delims("{[", "]}").ParseFiles("./t.tmpl")
对于html/template包,有一个很好用的功能:上下文感知。text/template没有该功能。上下文感知具体指的是根据所处环境css、js、html、url的path、url的query,自动进行不同格式的转义。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>{{ . }}</div>
</body>
</html>
package main
import (
// "text/template"
"html/template"
"net/http"
)
func indexHandleFunc(w http.ResponseWriter, r *http.Request) {
t, _ := template.ParseFiles("./index.tmpl")
data := `<script>alert("helloworld")</script>`
t.Execute(w, data)
}
func main() {
http.HandleFunc("/", indexHandleFunc)
http.ListenAndServe(":8080", nil)
}
运行程序,页面显示:<script>alert("helloworld")</script>
默认是不转义
不想转义的话,可以自行编写一个safe函数,手动返回一个template.HTML类型的内容
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>{{ .str1 }}</div>
<div>{{ .str2 | safe }}</div>
</body>
</html>
package main
import (
// "text/template"
"html/template"
"net/http"
)
func indexHandleFunc(w http.ResponseWriter, r *http.Request) {
t := template.New("index.tmpl")
t.Funcs(template.FuncMap{
"safe": func(str string) template.HTML {
return template.HTML(str)
},
}).ParseFiles("./index.tmpl")
m := map[string]interface{}{
"str1": `<script>alert("helloworld")</script>`,
"str2": `<a href = "http://baidu.com">baidu</a>`,
}
t.Execute(w, m)
}
package main
import (
"log"
"net/http"
)
func main() {
mux := http.DefaultServeMux
mux.Handle("/web/js/", http.StripPrefix("/web/js/", http.FileServer(http.Dir("static/js/"))))
mux.Handle("/web/css/", http.StripPrefix("/web/css/", http.FileServer(http.Dir("static/css/"))))
mux.Handle("/web/img/", http.StripPrefix("/web/img/", http.FileServer(http.Dir("static/img/"))))
log.Fatal(http.ListenAndServe(":8080", mux))
}
说明:static/js表示物理目录,浏览器访问http://localhost:8080/web/js/test.js即可访问到对应文件。
go.mod main.go static/css/main.css templates/index.html.tmpl title.txt
package main
import (
"embed"
"html/template"
"log"
"net/http"
)
// The go embed directive statement must be outside of function body
// Embed the file content as string.
//go:embed title.txt
var title string
// Embed the entire directory.
//go:embed templates
var indexHTML embed.FS
//go:embed static
var staticFiles embed.FS
func main() {
// Note the call to ParseFS instead of Parse
t, err := template.ParseFS(indexHTML, "templates/index.html.tmpl")
if err != nil {
log.Fatal(err)
}
// http.FS can be used to create a http Filesystem
var staticFS = http.FS(staticFiles)
fs := http.FileServer(staticFS)
// Serve static files
http.Handle("/static/", fs)
// Handle all other requests
http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
var path = req.URL.Path
log.Println("Serving request for path", path)
w.Header().Add("Content-Type", "text/html")
// respond with the output of template execution
t.Execute(w, struct {
Title string
Response string
}{Title: title, Response: path})
})
log.Println("Listening on :3000...")
// start the server
err = http.ListenAndServe(":3000", nil)
if err != nil {
log.Fatal(err)
}
}
<html>
<head>
<title>{{.Title}}</title>
<link rel="stylesheet" href="static/css/main.css">
</head>
<body>
<p>{{.Response}}</p>
<p>Powered by // go:embed</p>
</body>
</html>
This is the title.