本章将讨论 Go 的组合特性,以及 建立一个通用的调用 模板的方法
go-mega/03-template-advance.md at master · bonfy/go-mega · GitHub这个是原网站,我是在这里学的
仅写自己没没学过的
好的,出现了一个从没学过的东西
基础模板和功能模板,大概意思就是基础模板就是每个模块都会出现的字段,功能模板就是对于某个模块专门写的
所以我们将基础模板分离成一个单独文件,功能模板写成一个文件,然后我们需要编写一个函数遍历功能模块
我们首先解析一下这个文档
<html>
<head>
{{if .Title}}
<title>{{.Title}} - blog</title>
{{else}}
<title>Welcome to blog!</title>
{{end}}
</head>
<body>
<div>Blog: <a href="/">Home</a></div>
{{template "content" .}}
</body>
</html>
<a href = "/">Home</a>
: 是用来创建一个链接。
href = "/"
指定链接的目标地址,这里是网站的根目录
Home是链接的文本内容
{{template}}
指令用于执行另一个命名的模板,content 是模板的名称,表示一个独立的模板文件或代码块
{{define "content"}}
<h1>Hello,{{.User.Username}}!</h1>
{{range .Posts}}
<div><p>{{.User.Username}}says:<b>{{.Body}}</b></p></div>
{{end}}
{{end}}
{{define "content"}}
告诉模板解析器定义了一个名为“content”的模板
这里说一下网站里面的代码可以在终端里面都可以运行,但是直接在goland软件里面运行是没有办法成功的
package main
import (
"html/template"
"io/ioutil"
"net/http"
"os"
)
// User struct
type User struct {
Username string
}
// Post struct
type Post struct {
User
Body string
}
// IndexViewModel struct
type IndexViewModel struct {
Title string
User
Posts []Post
}
// PopulateTemplates func
// Create map template name to template.Template
func PopulateTemplates() map[string]*template.Template {
const basePath = "templates" //定义模板文件的基本路径
result := make(map[string]*template.Template)
//将基本布局模板‘_base.html’,并将其存储在变量‘layout’中
layout := template.Must(template.ParseFiles(basePath + "/_base.html"))
dir, err := os.Open(basePath + "/content") //打开目标文件夹
if err != nil {
panic("Failed to open template blocks directory:" + err.Error())
}
fis, err := dir.ReadDir(-1) //Readdir(-1)会读取目录中的文件信息,并返回一个文件信息的切片
/*
如果ReadDir里面传入的是一个正整数n,表示最多读取n个文件
fis是读取到的文件信息切片,每个元素代表目录中的一个文件的信息
type DirEntry interface {
Name() string
IsDir() bool
Type() FileMode
Info() (FileInfo, error)
}
*/
if err != nil {
panic("Failed to read contents of content directory:" + err.Error())
}
for _, fi := range fis {
func() {
f, err := os.Open(basePath + "/content/" + fi.Name())//注意文件的路径不能错了
if err != nil {
panic("Failed to open template '" + fi.Name() + "'")
}
defer f.Close()
content, err := ioutil.ReadAll(f) //读这个文件
if err != nil {
panic("Failed to read content from file'" + fi.Name())
}
tmpl := template.Must(layout.Clone())
/*
使用layout.Clone()复制基本布局模板,然后将读取的内容解析为模板
并于基本布局合并
*/
_, err = tmpl.Parse(string(content))
if err != nil {
panic("Failed to parse contents of '" + fi.Name() + "' as template")
}
result[fi.Name()] = tmpl
}() //这里定义函数
}
return result
}
/*
这里总结一下:
首先将基本模板存在一个变量中
然后打开功能模板的文件夹,将该文件夹中的所有文件的信息都记录在一个变量a中
然后遍历a,对所有功能模板进行解析,结合基本模板成为新的模板
将这个新的模板存在map中
键:文件的路径
值:结合模板
得到一个map
*/
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
u1 := User{Username: "bonfy"}
u2 := User{Username: "rene"}
posts := []Post{
Post{User: u1, Body: "Beautiful day in Portland!"},
Post{User: u2, Body: "The Avengers movie was so cool!"},
}
v := IndexViewModel{Title: "Homepage", User: u1, Posts: posts}
templates := PopulateTemplates()
templates["index.html"].Execute(w, &v)
})
http.ListenAndServe(":8888", nil)
}