• GO语言html模板


    模板

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

    示例

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

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Hello</title>
    </head>
    <body>
        <p>Hello {{.}}!</p>
    </body>
    </html>
    

    GO server端:

    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
        }
    }
    

    效果:

    模板语法

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

    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Hello</title>
    </head>
    <body>
        <p>Hello {{.Name}}!</p>
        <p>年龄 {{.Age}}!</p>
        <p>性别 {{.Male}}!</p>
    </body>
    </html>
    

    GO server端:

    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
        }
    }
    

    效果:

    注释

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

    变量

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

    $variable := pipeline
    

    示例:

    <body>
        <p>Hello {{.Name}}!</p>
        <p>年龄 {{.Age}}!</p>
        <p>性别 {{.Male}}!</p>
        {{ $age := . }}
        {{ $age.Age }}
    </body>
    

    条件判断

    初始语法:

    {{if pipeline}} T1 {{end}}
    {{if pipeline}} T1 {{else}} T0 {{end}}
    {{if pipeline}} T1 {{else if pipeline}} T0 {{end}}
    

    示例:

    <body>
        <p>Hello {{.Name}}!</p>
        <p>年龄 {{.Age}}!</p>
        <p>性别 {{.Male}}!</p>
        {{ $age := . }}
        {{ $age.Age }}
        {{if gt .Age 18}}
        <div>成年啦!</div>
        {{else}}
        <div>快乐成长!</div>
        {{end}}
    </body>
    

    比较函数

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

    eq      如果arg1 == arg2则返回真
    ne      如果arg1 != arg2则返回真
    lt      如果arg1 < arg2则返回真
    le      如果arg1 <= arg2则返回真
    gt      如果arg1 > arg2则返回真
    ge      如果arg1 >= arg2则返回真
    

    range

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

    {{range pipeline}} T1 {{end}}
    如果pipeline的值其长度为0,不会有任何输出
    
    {{range pipeline}} T1 {{else}} T0 {{end}}
    如果pipeline的值其长度为0,则会执行T0。
    

    map示例:

    PeopleMap := map[int]People{
            1: {"Ares", 18, "男"},
            2: {"龙猫", 28, "女"},
        }
    tem.Execute(w, PeopleMap)
    

    切片示例:

    PeopleSlice := []People{
            {"Ares", 18, "男"},
            {"龙猫", 28, "女"},
        }
        tem.Execute(w, PeopleSlice)
    

    HTML模板:

    <body>
    <table border="1">
        <thead>
        <tr>
            <th>序号</th>
            <th>姓名</th>
            <th>年龄</th>
            <th>性别</th>
        </tr>
        </thead>
        <tbody>
        {{range $index, $user := .}}
        <tr>
            <td>{{$index}}</td>
            <td>{{$user.Name}}</td>
            <td>{{$user.Age}}</td>
            <td>{{$user.Male}}</td>
        </tr>
        {{end}}
        </tbody>
    </table>
    </body>
    

    效果:

    预定义函数

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

    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[1][2][3]的值;每个被索引的主体必须是数组、切片或者字典。
    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,模板执行会中断并返回给调用模板执行者该错误;
    

    参考:GO语言标准库
    示例:

    <p>{{index . 1}}</p>
        <p>切片长度: {{len .}}</p>
        <p>
            {{with index . 1}}
            {{printf "姓名:%s 年龄:%d 性别:%s" .Name .Age .Male}}
            {{end}}
        </p>
    

    效果:

    自定义函数

    自定义一个book函数:

    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 := map[int]Book{
            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)
    }
    

    html:

    <body>
        <p>
        {{with index . 1}}
        <p>{{book .Name}}</p>
        {{end}}
        </p>
        <p>
        {{with index . 2}}
        <p>{{book .Name}}</p>
        {{end}}
        </p>
    </body>
    

    效果:

    模板嵌套

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

    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)
    }
    

    index.html:

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

    test.html:

    <body>
    <ol>
        <li>嵌套模板</li>
        <li>out模板</li>
    </ol>
    </body>
    

    效果:

  • 相关阅读:
    Stm32设置串口300波特率
    STM32F103ZET6移植FreeRTOS过程
    什么时候该用裸机?什么时候该用RTOS?
    又到了立flag时间
    关于掉电数据保存的心得
    一个教训
    下个月回国给自己定目标
    GPRS模块/4G开发过程
    ftp登陆失败,check pass; user unknown
    python深浅拷贝
  • 原文地址:https://www.cnblogs.com/aresxin/p/GO-yu-yanhtml-mo-ban.html
Copyright © 2020-2023  润新知