好好上班 發表於 2019-6-10 23:45:00

GO语言html模板

<h2 id="toc_0">模板</h2>

<p>一个模板是一个字符串或一个文件,里面包含了一个或多个由双花括号包含的{{action}}对象。大部分的字符串只是按面值打印,但是对于actions部分将触发其它的行为。每个actions都包含了一个用模板语言书写的表达式,一个action虽然简短但是可以输出复杂的打印值,模板语言包含通过选择结构体的成员、调用函数或方法、表达式控制流if-else 语句range循环语句,还有其它实例化模板等诸多特性。Action内部不能有换行,但注释可以有换行。</p>

<h3 id="toc_1">示例</h3>

<p>模板执行时会遍历结构并将指针表示为’.‘(称之为”dot”)指向运行过程中数据结构的当前位置的值。<br>
用作模板的输入文本必须是utf-8编码的文本。<br>
Html示例:</p>

<pre><code class="language-go">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;title&gt;Hello&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;p&gt;Hello {{.}}!&lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>

<p>GO server端:</p>

<pre><code class="language-go">func sayHi(w http.ResponseWriter,r *http.Request){
    // 解析指定文件生成模板对象
    tem,err := template.ParseFiles("xx/hello.html")
    if err != nil{
      fmt.Println("读取文件失败,err",err)
      return
    }
    // 利用给定数据渲染模板,并将结果写入w
    tem.Execute(w,"Ares")
}
func main(){
    http.HandleFunc("/",sayHi)
    err := http.ListenAndServe("127.0.0.1:8888",nil)
    if err != nil{
      fmt.Println("监听失败,err",err)
      return
    }
}
</code></pre>

<p>效果:<br>
<img src="https://img2018.cnblogs.com/blog/830693/201906/830693-20190610234435738-1656145622.jpg" alt="" style="width: 291px"></p>

<h3 id="toc_2">模板语法</h3>

<p>模板语法都包含在{{和}}中间,其中{{.}}中的点表示当前对象。<br>
当我们传入一个结构体对象时,我们可以根据.来访问结构体的对应字段。Html示例:</p>

<pre><code class="language-go">&lt;html lang="en"&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;title&gt;Hello&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;p&gt;Hello {{.Name}}!&lt;/p&gt;
    &lt;p&gt;年龄 {{.Age}}!&lt;/p&gt;
    &lt;p&gt;性别 {{.Male}}!&lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>

<p>GO server端:</p>

<pre><code class="language-go">type People struct {
    Name string
    Age int
    Male string
}
func sayHi(w http.ResponseWriter,r *http.Request){
    // 解析指定文件生成模板对象
    tem,err := template.ParseFiles("xx/hello.html")
    if err != nil{
      fmt.Println("读取文件失败,err",err)
      return
    }
    // 利用给定数据渲染模板,并将结果写入w
    People := People{
      Name:"Ares",
      Age:28,
      Male:"男",
    }
    tem.Execute(w,People)
}
func main(){
    http.HandleFunc("/",sayHi)
    err := http.ListenAndServe("127.0.0.1:8888",nil)
    if err != nil{
      fmt.Println("监听失败,err",err)
      return
    }
}
</code></pre>

<p>效果:<br>
<img src="https://img2018.cnblogs.com/blog/830693/201906/830693-20190610234435802-1359325000.jpg" alt="" style="width: 269px"></p>

<h3 id="toc_3">注释</h3>

<p>{{/* a comment */}}<br>
可以多行。注释不能嵌套。</p>

<h3 id="toc_4">变量</h3>

<p>Action里可以初始化一个变量来捕获管道的执行结果。初始化语法如下:</p>

<pre><code class="language-go">$variable := pipeline
</code></pre>

<p>示例:</p>

<pre><code class="language-go">&lt;body&gt;
    &lt;p&gt;Hello {{.Name}}!&lt;/p&gt;
    &lt;p&gt;年龄 {{.Age}}!&lt;/p&gt;
    &lt;p&gt;性别 {{.Male}}!&lt;/p&gt;
    {{ $age := . }}
    {{ $age.Age }}
&lt;/body&gt;
</code></pre>

<h3 id="toc_5">条件判断</h3>

<p>初始语法:</p>

<pre><code class="language-go">{{if pipeline}} T1 {{end}}
{{if pipeline}} T1 {{else}} T0 {{end}}
{{if pipeline}} T1 {{else if pipeline}} T0 {{end}}
</code></pre>

<p>示例:</p>

<pre><code class="language-go">&lt;body&gt;
    &lt;p&gt;Hello {{.Name}}!&lt;/p&gt;
    &lt;p&gt;年龄 {{.Age}}!&lt;/p&gt;
    &lt;p&gt;性别 {{.Male}}!&lt;/p&gt;
    {{ $age := . }}
    {{ $age.Age }}
    {{if gt .Age 18}}
    &lt;div&gt;成年啦!&lt;/div&gt;
    {{else}}
    &lt;div&gt;快乐成长!&lt;/div&gt;
    {{end}}
&lt;/body&gt;
</code></pre>

<h3 id="toc_6">比较函数</h3>

<p>布尔函数会将任何类型的零值视为假,其余视为真。</p>

<pre><code class="language-go">eq      如果arg1 == arg2则返回真
ne      如果arg1 != arg2则返回真
lt      如果arg1 &lt; arg2则返回真
le      如果arg1 &lt;= arg2则返回真
gt      如果arg1 &gt; arg2则返回真
ge      如果arg1 &gt;= arg2则返回真
</code></pre>

<h3 id="toc_7">range</h3>

<p>使用range关键字进行遍历,有以下两种写法,其中pipeline的值必须是数组、切片、字典或者通道。<br>
基本语法:</p>

<pre><code class="language-go">{{range pipeline}} T1 {{end}}
如果pipeline的值其长度为0,不会有任何输出

{{range pipeline}} T1 {{else}} T0 {{end}}
如果pipeline的值其长度为0,则会执行T0。
</code></pre>

<p>map示例:</p>

<pre><code class="language-go">PeopleMap := mapPeople{
      1: {"Ares", 18, "男"},
      2: {"龙猫", 28, "女"},
    }
tem.Execute(w, PeopleMap)
</code></pre>

<p>切片示例:</p>

<pre><code class="language-go">PeopleSlice := []People{
      {"Ares", 18, "男"},
      {"龙猫", 28, "女"},
    }
    tem.Execute(w, PeopleSlice)
</code></pre>

<p>HTML模板:</p>

<pre><code class="language-go">&lt;body&gt;
&lt;table border="1"&gt;
    &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;序号&lt;/th&gt;
      &lt;th&gt;姓名&lt;/th&gt;
      &lt;th&gt;年龄&lt;/th&gt;
      &lt;th&gt;性别&lt;/th&gt;
    &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
    {{range $index, $user := .}}
    &lt;tr&gt;
      &lt;td&gt;{{$index}}&lt;/td&gt;
      &lt;td&gt;{{$user.Name}}&lt;/td&gt;
      &lt;td&gt;{{$user.Age}}&lt;/td&gt;
      &lt;td&gt;{{$user.Male}}&lt;/td&gt;
    &lt;/tr&gt;
    {{end}}
    &lt;/tbody&gt;
&lt;/table&gt;
&lt;/body&gt;
</code></pre>

<p>效果:<br>
<img src="https://img2018.cnblogs.com/blog/830693/201906/830693-20190610234435898-978361874.jpg" alt="" style="width: 253px"></p>

<h3 id="toc_8">预定义函数</h3>

<p>执行模板时,函数从两个函数字典中查找:首先是模板函数字典,然后是全局函数字典。一般不在模板内定义函数,而是使用Funcs方法添加函数到模板里。</p>

<pre><code class="language-yaml">and
    函数返回它的第一个empty参数或者最后一个参数;
    就是说"and x y"等价于"if x then y else x";所有参数都会执行;
or
    返回第一个非empty参数或者最后一个参数;
    亦即"or x y"等价于"if x then x else y";所有参数都会执行;
not
    返回它的单个参数的布尔值的否定
len
    返回它的参数的整数类型长度
index
    执行结果为第一个参数以剩下的参数为索引/键指向的值;
    如"index x 1 2 3"返回x的值;每个被索引的主体必须是数组、切片或者字典。
print
    即fmt.Sprint
printf
    即fmt.Sprintf
println
    即fmt.Sprintln
html
    返回其参数文本表示的HTML逸码等价表示。
urlquery
    返回其参数文本表示的可嵌入URL查询的逸码等价表示。
js
    返回其参数文本表示的JavaScript逸码等价表示。
call
    执行结果是调用第一个参数的返回值,该参数必须是函数类型,其余参数作为调用该函数的参数;
    如"call .X.Y 1 2"等价于go语言里的dot.X.Y(1, 2);
    其中Y是函数类型的字段或者字典的值,或者其他类似情况;
    call的第一个参数的执行结果必须是函数类型的值(和预定义函数如print明显不同);
    该函数类型值必须有1到2个返回值,如果有2个则后一个必须是error接口类型;
    如果有2个返回值的方法返回的error非nil,模板执行会中断并返回给调用模板执行者该错误;
</code></pre>

<p>参考:GO语言标准库<br>
示例:</p>

<pre><code class="language-go">&lt;p&gt;{{index . 1}}&lt;/p&gt;
    &lt;p&gt;切片长度: {{len .}}&lt;/p&gt;
    &lt;p&gt;
      {{with index . 1}}
      {{printf "姓名:%s 年龄:%d 性别:%s" .Name .Age .Male}}
      {{end}}
    &lt;/p&gt;
</code></pre>

<p>效果:<br>
<img src="https://img2018.cnblogs.com/blog/830693/201906/830693-20190610234436042-857955155.jpg" alt="" style="width: 347px"></p>

<h3 id="toc_9">自定义函数</h3>

<p>自定义一个book函数:</p>

<pre><code class="language-go">type Book struct {
    Name string
    Author string
    Price float32
}

func info(w http.ResponseWriter,r *http.Request){
    // 打开一个模板文件
    htmlByte,err := ioutil.ReadFile("./info.html")
    if err != nil{
      fmt.Println("读取html文件失败,err",err)
      return
    }
    // 1. 自定义一个函数
    // 自定义一个书籍的模板函数
    bookFunc := func(arg string) (string, error) {
      return arg + "真好看!", nil
    }
    // 2. 把自定义的函数告诉模板系统
    // template.New("info") // 创建一个Template对象
    // template.New("info").Funcs(template.FuncMap{"book": bookFunc}) // 给模板系统追加自定义函数
    // 解析模板
    t,err := template.New("info").Funcs(template.FuncMap{"book": bookFunc}).Parse(string(htmlByte))
    if err != nil{
      fmt.Println("parse html文件失败,err",err)
      return
    }
    BookMap := mapBook{
      1:{"跟Ares一起学GO","Ares",9.9},
      2:{"斗破苍穹","Ares1",99.9},
    }
    t.Execute(w,BookMap)
}

func main(){
    http.HandleFunc("/info",info)
    http.ListenAndServe("127.0.0.1:8888",nil)
}
</code></pre>

<p>html:</p>

<pre><code class="language-go">&lt;body&gt;
    &lt;p&gt;
    {{with index . 1}}
    &lt;p&gt;{{book .Name}}&lt;/p&gt;
    {{end}}
    &lt;/p&gt;
    &lt;p&gt;
    {{with index . 2}}
    &lt;p&gt;{{book .Name}}&lt;/p&gt;
    {{end}}
    &lt;/p&gt;
&lt;/body&gt;
</code></pre>

<p>效果:<br>
<img src="https://img2018.cnblogs.com/blog/830693/201906/830693-20190610234436055-487951587.jpg" alt="" style="width: 303px"></p>

<h3 id="toc_10">模板嵌套</h3>

<p>我们可以在template中嵌套其他的template。这个template可以是单独的文件,也可以是通过define定义的template.</p>

<pre><code class="language-go">func index(w http.ResponseWriter,r * http.Request){
    t , err := template.ParseFiles("./index.html","./test.html")
    if err != nil{
      fmt.Println("读取html文件失败,err",err)
      return
    }
    t.Execute(w,nil)
}
func main(){
    http.HandleFunc("/",index)
    http.ListenAndServe("127.0.0.1:8888",nil)
}
</code></pre>

<p>index.html:</p>

<pre><code class="language-go">&lt;body&gt;
&lt;h1&gt;测试嵌套template语法&lt;/h1&gt;
&lt;hr&gt;
{{template "test.html"}}
&lt;hr&gt;
{{/* 在index.html这个模板中调用了另外一个模板:index.html */}}
{{template "inside.html"}}
&lt;/body&gt;
&lt;/html&gt;
      
{{/* 在index.html这个模板中定义了另外一个模板:inside.html */}}
{{ define "inside.html"}}
&lt;h1&gt;inside.html&lt;/h1&gt;
&lt;ol&gt;
    &lt;li&gt;吃饭&lt;/li&gt;
    &lt;li&gt;睡觉&lt;/li&gt;
    &lt;li&gt;打豆豆&lt;/li&gt;
&lt;/ol&gt;
{{end}}
</code></pre>

<p>test.html:</p>

<pre><code class="language-go">&lt;body&gt;
&lt;ol&gt;
    &lt;li&gt;嵌套模板&lt;/li&gt;
    &lt;li&gt;out模板&lt;/li&gt;
&lt;/ol&gt;
&lt;/body&gt;
</code></pre>

<p>效果:<br>
<img src="https://img2018.cnblogs.com/blog/830693/201906/830693-20190610234436065-546924180.jpg" alt="" style="width: 375px"></p>

</div>
<div id="MySignature" role="contentinfo">
    <div>作者:Mr.Ares</div>
<div>出处:http://www.cnblogs.com/aresxin/</div>
<div>个性签名:许多人的付出都是浅尝辄止!</div><br><br>
来源:https://www.cnblogs.com/aresxin/p/GO-yu-yanhtml-mo-ban.html
頁: [1]
查看完整版本: GO语言html模板