Go模板总结

模板引擎

  • 模板引擎是 Web 编程中必不可少的⼀个组件。模板能分离逻辑和数据,使得逻辑简洁清晰,并且模板可复⽤。

  • Go模板总结_第1张图片

  • ⽆逻辑模板引擎
    类模板引擎只进⾏字符串的替换,⽆其它逻辑。

  • 嵌⼊逻辑模板引擎
    此类模板引擎可以在模板中嵌⼊逻辑,实现流程控制/循环等。

    定义模板

package main

import (
	"log"
	"net/http"
	"os"
	"text/template"
)

type User struct {
	Name string
	Age  int
}

// 解析字符串
func stringLiteralTemplate() {
	s := "My name is {{ .Name }}. I am {{ .Age }} years old.\n"
	// 创建模板  并解析上面的s字符串
	t, err := template.New("test").Parse(s)
	if err != nil {
		log.Fatal("Parse string literal template error:", err)
	}

	u := User{Name: "lianshi", Age: 18}

	// 去执行渲染  把数据按规则塞进模板
	err = t.Execute(os.Stdout, u)
	if err != nil {
		log.Fatal("Execute string literal template error:", err)
	}
}

// 解析文件 注意用终端执行
func fileTemplate() {
	//t, err := template.ParseFiles("test")
	t, err := template.ParseFiles("index.html")
	if err != nil {
		log.Fatal("Parse file template error:", err)
	}
	u := User{Name: "ls", Age: 18}
	err = t.Execute(os.Stdout, u)
	if err != nil {
		log.Fatal("Execute file template error:", err)
	}
}

func indexHandler(w http.ResponseWriter, r *http.Request) {

	// 前后端不分离 后端利用模板渲染
	t, err := template.ParseFiles("index.html")
	if err != nil {
		log.Fatal("Parse file template error:", err)
	}
	u := User{Name: "ls", Age: 18}
	err = t.Execute(w, u)
	if err != nil {
		log.Fatal("Execute file template error:", err)
	}

	// 前后端分离,返回Json格式的数据
	// 优点:减少网络消耗和耗时
	// 缺点:页面都是游览器渲染,不利于数据处理,排序等
	//u := User{Name: "ls", Age: 18}

}

// 点动作
func main() {
	//stringLiteralTemplate()
	//fileTemplate()

	mux := http.NewServeMux()
	mux.HandleFunc("/index", indexHandler)

	server := &http.Server{
		Addr:    ":8080",
		Handler: mux,
	}

	if err := server.ListenAndServe(); err != nil {
		log.Fatal(err)
	}

}

模板动作

  • 点动作
  • 条件动作
  • 迭代动作
  • 设置动作
  • 包含动作

条件动作

package main

import (
	"log"
	"math/rand"
	"os"
	"text/template"
	"time"
)

type AgeInfo struct {
	Age           int
	GreaterThan60 bool
	GreaterThan40 bool
}

// 条件动作
func main() {
	t, err := template.ParseFiles("test")
	if err != nil {
		log.Fatal("Parse error:", err)
	}

	rand.Seed(time.Now().Unix())
	age := rand.Intn(100)

	info := AgeInfo{
		Age:           age,
		GreaterThan60: age > 60,
		GreaterThan40: age > 40,
	}

	err = t.Execute(os.Stdout, info)
	if err != nil {
		log.Fatal("Execute error:", err)
	}

}

迭代动作

package main

import (
	"log"
	"os"
	"text/template"
)

type Item struct {
	Name  string
	Price int
}

// 迭代动作
func main() {
	t, err := template.ParseFiles("test")
	if err != nil {
		log.Fatal("Parse error:", err)
	}

	items := []Item{
		{"iPhone", 699},
		{"iPad", 799},
		{"iWatch", 199},
		{"MacBook", 999},
	}
	err = t.Execute(os.Stdout, items)
	if err != nil {
		log.Fatal("Execute error:", err)
	}
}

设置动作

package main

import (
	"log"
	"os"
	"text/template"
)

type User struct {
	Name string
	Age  int
}
type Pet struct {
	Name  string
	Age   int
	Owner User
}

// 传入的数据中,嵌套另外一个结构,则模板中 可以使用 with 关键字 来简化语法
func main() {
	t, err := template.ParseFiles("test")
	if err != nil {
		log.Fatal("Parse error:", err)
	}

	p := Pet{
		Name: "Orange",
		Age:  2,
		Owner: User{
			Name: "ls",
			Age:  18,
		},
	}

	err = t.Execute(os.Stdout, p)
	if err != nil {
		log.Fatal("Execute error:", err)
	}
}

test

Pet Info:
Name: {{ .Name }}
Age: {{ .Age }}
Owner:{{ with .Owner }}
 Name: {{ .Name }}
 Age: {{ .Age }}
{{ end }}

包含动作

package main

import (
	"log"
	"os"
	"text/template"
)

// 模板之间的嵌套——包含动作
func main() {
	t, err := template.ParseFiles("test1", "test2")
	if err != nil {
		log.Fatal("Parse error:", err)
	}
	err = t.Execute(os.Stdout, "test data")
	if err != nil {
		log.Fatal("Execute error:", err)
	}
}

test1

This is in test1.
{{ template "test2" }}
{{ template "test2" . }}

test2

This is in test2.
Get: {{ . }}.

参数

package main

import (
	"log"
	"os"
	"text/template"
)

type User struct {
	FirstName string
	LastName  string
}

func (u User) FullName() string {
	return u.FirstName + " " + u.LastName
}
func main() {
	t, err := template.ParseFiles("test")
	if err != nil {
		log.Fatal("Parse error:", err)
	}
	err = t.Execute(os.Stdout, User{FirstName: "ls", LastName: "lianshi"})
	if err != nil {
		log.Fatal("Execute error:", err)
	}
}

My full name is {{ .FullName }}.

输出:
My full name is ls lianshi.

管道

在⼀个链式管道中,每个命令的结果会作为下⼀个命令的最后⼀个参数。最后⼀个命令的结果作为整个管道的值

package main

import (
	"log"
	"os"
	"text/template"
)

type Item struct {
	Name  string
	Price float64
	Num   int
}

func (item Item) Total() float64 {
	return item.Price * float64(item.Num)
}

func main() {
	t, err := template.ParseFiles("test")
	if err != nil {
		log.Fatal("Parse error:", err)
	}

	item := Item{"iPhone", 699.99, 2}
	err = t.Execute(os.Stdout, item)
	if err != nil {
		log.Fatal("Execute error:", err)
	}
}

test

Product: {{ .Name }}
Price:{{ .Price }}
Num: {{ .Num }}
Total:{{ .Total | printf "%.2f" }}

输出:

Product: iPhone
Price:699.99
Num: 2
Total:1399.98

变量

  • 在动作中,可以⽤管道的值定义⼀个变量。
$variable := pipeline

函数

Go 模板提供了⼤量的预定义函数,如果有特殊需求也可以实现⾃定义函数。模板执⾏时,遇到函数调⽤,先从模板⾃定义函数表中查找,⽽后查找全局函数表。

自定义函数

package main

import (
	"log"
	"os"
	"text/template"
	"time"
)

func formatDate(t time.Time) string {
	return t.Format("2016-01-02")
}

func main() {
	funcMap := template.FuncMap{
		"fdate": formatDate,
	}

	t := template.New("test").Funcs(funcMap)

	t, err := t.ParseFiles("test")
	if err != nil {
		log.Fatal("Parse errr:", err)
	}

	err = t.Execute(os.Stdout, time.Now())
	if err != nil {
		log.Fatal("Exeute error:", err)
	}
}

test

Today is {{ . | fdate }}.

输出:

Today is 12116-11-12.
  • 必须先创建模板,调⽤ Funcs 设置⾃定义函数,然后再解析模板。

创建模板

  • 模板的创建⽅式:
    先调⽤ template.New 创建模板,然后使⽤ Parse/ParseFiles 解析模板内容。
  • 直接使⽤ template.ParseFiles 创建并解析模板⽂件。

第一种:

package main
import (
 "log"
 "os"
 "text/template"
)
func main() {
 t := template.New("test")
 t, err := t.ParseFiles("test1")
 if err != nil {
 log.Fatal("Parse error:", err)
 }
 err = t.Execute(os.Stdout, nil)
 if err != nil {
 log.Fatal("Execute error:", err)
 } }

出错:名字不一样
执⾏ ParseFiles ⽅法时,每个⽂件都会⽣成⼀个模板。只有⽂件基础名与模板名相同时,该⽂件的内容才会解析到主模板中。这也是上⾯的程序执⾏失败的原因——主模板为空。

应该作为参数传进去:

package main

import (
	"log"
	"os"
	"text/template"
)

func main() {
	t := template.New("test")
	t, err := t.ParseFiles("test1")

	if err != nil {
		log.Fatal("in associatedTemplate Parse error:", err)
	}

	err = t.ExecuteTemplate(os.Stdout, "test1", nil)
	if err != nil {
		log.Fatal("in associatedTemplate Execute error:", err)
	}
}

第二种:将创建和解析两步合并在⼀起了。

t, err := template.ParseFiles("file1", "file2", "file3")

等价于

t := template.New("file1")
t, err := t.ParseFiles("file1", "file2", "file3")

嵌套模板

在⼀个模板⽂件中还可以通过 {{ define }} 动作定义其它的模板,这些模板就是嵌套模板。模板定义必须在模板内容的最顶层,像 Go 程序中的全局变量⼀样。
嵌套模板⼀般⽤于布局(layout)。很多⽂本的结构其实⾮常固定,例如邮件有标题和正⽂,⽹⻚有⾸部、正⽂和尾部等。 我们可以为这些固定结构的每部分定义⼀个模板。

{{ define "layout" }}
This is body.
{{ template "content" . }}
{{ end }}
{{ define "content" }}
This is {{ . }} content.
{{ end }}

上⾯定义了两个模板 layout 和 content , layout 中使⽤了 content 。执⾏这种⽅式定义的模板必须使⽤ ExecuteTemplate ⽅法:

func main() {
	t, err := template.ParseFiles("layout.tmpl")
	if err != nil {
		log.Fatal("Parse error:", err)
	}
	err = t.ExecuteTemplate(os.Stdout, "layout", "amazing")
	if err != nil {
		log.Fatal("Execute error:", err)
	}
}

块动作

块动作其实就是定义⼀个默认模板,语法如下:

{{ block "name" arg }}
T1
{{ end }}

它就等价于定义⼀个模板,然后⽴即使⽤它

你可能感兴趣的:(Go)