组件开发


组件是一个页面UI组件的抽象,包括了html以及其他资源。开发一个组件需要实现以下接口:

type Component interface {
    // GetTemplate 返回了一个golang的模板对象,以及模板名
    GetTemplate() (*template.Template, string)

    // GetAssetList 返回了组件中使用的资源列表,为一个数组。
    // 数组中的资源路径与事实应用的路径对应关系如下:
    //
    // {{.UrlPrefix}}/assets/login/css/bootstrap.min.css => login/css/bootstrap.min.css
    //
    // 例子:
    // https://github.com/GoAdminGroup/go-admin/blob/master/template/login/assets_list.go
    GetAssetList() []string

    // GetAsset 根据提供的资源路径返回资源的内容。
    // 比如:参数为 asset/login/dist/all.min.css,返回对应的css内容。
    //
    // See: http://github.com/jteeuwen/go-bindata
    GetAsset(string) ([]byte, error)

    // GetContent 返回组件渲染后的html
    GetContent() template.HTML

    // IsAPage 返回该组件是否为一个页面
    IsAPage() bool

    // GetName 返回组件名字
    GetName() string
}

假设我们要开发一个MagicBox组件。我们可以新建一个magic_box文件夹,文件夹下新建以下文件:

.
├── assets
│   ├── dist
│   │   └── img
│   └── src
│       ├── img
│       ├── css
│       └── js
├── magic_box.go
└── magic_box.tmpl

tmpl文件编写我们的html文件,assets/src下放我们的前端资源文件,我们会使用到adm工具,将我们的资源文件首先合并,然后编译成go文件,从而可以给我们的MagicBox对象调用。

编写完毕后,我们执行以下命令进行编译:

# 合并js资源
adm combine js --path=./assets/src/js/ --out=./assets/dist/all.min.js
# 合并css资源
adm combine css --path=./assets/src/css/ --out=./assets/dist/all.min.css
# 将dist目录下静态资源编译为一个go文件与一个资源列表文件
adm compile asset --path=./assets/dist/ --out=./ --pa=magic_box

我们在magic_box.go中实现一个组件:

package magic_box

type MagicBox struct {
    Name string
}

func Get() *MagicBox {
    return &MagicBox{
        Name: "magic_box",
    }
}

func (l *MagicBox) GetTemplate() (*template.Template, string) {
    tmpl, err := template.New("magic_box").
        Funcs(DefaultFuncMap).
        Parse(List["magic_box"])

    if err != nil {
        logger.Error("magic box get template error: ", err)
    }

    return tmpl, "magic_box"
}

func (l *MagicBox) GetAssetList() []string               { return AssetList }
func (l *MagicBox) GetAsset(name string) ([]byte, error) { return Asset(name[1:]) }
func (l *MagicBox) GetName() string                      { return "magic_box" }
func (l *MagicBox) IsAPage() bool                        { return false }

func (l *MagicBox) GetContent() template.HTML {
    buffer := new(bytes.Buffer)
    tmpl, defineName := l.GetTemplate()
    err := tmpl.ExecuteTemplate(buffer, defineName, l)
    if err != nil {
        logger.Error("magic box component, compose html error:", err)
    }
    return template.HTML(buffer.String())
}

这里我们就开发完毕了。

接着我们就可以加载该组件进行使用:

package main

import (
    _ "github.com/GoAdminGroup/go-admin/adapter/gin"        
    _ "github.com/GoAdminGroup/go-admin/adapter/gin"
    _ "github.com/GoAdminGroup/go-admin/modules/db/drivers/mysql"

    "github.com/GoAdminGroup/components/login"
    "github.com/GoAdminGroup/go-admin/engine"
    "github.com/GoAdminGroup/go-admin/examples/datamodel"
    "github.com/GoAdminGroup/go-admin/template"
    "github.com/GoAdminGroup/go-admin/plugins/admin"
    "github.com/gin-gonic/gin"
    "io/ioutil"
)

func main() {
    r := gin.Default()

    gin.SetMode(gin.ReleaseMode)
    gin.DefaultWriter = ioutil.Discard

    eng := engine.Default()
    adminPlugin := admin.NewAdmin(datamodel.Generators)
    adminPlugin.AddGenerator("user", datamodel.GetUserTable)

    // 在这里进行加载
    template.AddComp(magic_box.Get())

    if err := eng.AddConfigFromJson("./config.json").
        AddPlugins(adminPlugin).
        Use(r); err != nil {
        panic(err)
    }

    // 加载完后,在你的逻辑函数中使用:magic_box.GetContent() 返回内容使用。

    r.Static("/uploads", "./uploads")

    _ = r.Run(":9033")
}