A闪的 BLOG 技术与人文
渲染模板在Jet中称之为“执行”,在准备好即将渲染的模板文件和变量渲染为最终的HTML字符。
下面这段代码是将名称为home.jet
的模板渲染为网页的使用方式。
templateName := "home.jet"
t, err := set.GetTemplate(templateName)
if err != nil {
// template could not be loaded
}
var w bytes.Buffer // needs to conform to io.Writer interface (like gin's context.Writer for example)
vars := make(jet.VarMap)
if err = t.Execute(&w, vars, nil); err != nil {
// error when executing template
}
需要注意上面代码中的vars
和第三个参数,此处为nil
,接下来解释参数的作用。
加载模板
当实例化模板对象的时候,Set
可以返回一个模板对象。但此时模板引擎并不会立刻搜索并加载模板文件。模板文件目录树如下:
|- main.go
|- README.go
|- views
|- common
| |- _footer.jet
| |- _menu.jet
|- auth
| |- _logo.jet
| |- login.jet
|- home.jet
|- layouts
|- application.jet
在Set
初始化时你应该指定模板所在的目录位置,下面这行代码写在main.go
中。
var viewSet = jet.NewHTMLSet("./views")
Jet的模板加载是需要制定模板文件路径的,如果你要使用login.jet
模,那应该像下面这样使用。
t, err := viewSet.GetTemplate("auth/login.jet")
Jet加载模板并解析后会缓存解析结果,所以模板的解析只会执行一次。
开发模式中重新加载模板
当你在开发过程中,需要反复调试模板内容。所以模板缓存功能需要关闭,你可以设置开发模式来关闭模板缓存。
viewSet.SetDevelopmentMode(true)
Jet建议在线上业务中,关闭开发者模块,开启模板缓存来提高性能。
模板渲染中使用变量
当模板引擎渲染后,需要一个io.Writer
对象以及变量和上下文。变量jet.VarMap
是一个map对象,里面存储着模板中所需要使用的变量名以及对应的值。你可以使用Set(key, value)
来添加对应的数据。
vars := make(jet.VarMap)
vars.Set("user", &User{})
值得注意的是,jet.VarMap
是map[string]reflect.Value
的重命名。如果在多个goroutines中使用同一个jet.VarMap
对象,则是不安全的。你应该来自行处理或者增加竞争锁来保证业务正常。
下面是一个互斥的基本实现,你可以参考来使用它。
// VarMapMx defines a mutex-protected jet.VarMap that's usable concurrently.
type VarMapMx struct {
mx sync.RWMutex
varMap jet.VarMap
}
// NewVarMapMx returns an initialized VarMapMx instance that is ready to be used.
func NewVarMapMx() *VarMapMx {
return &VarMapMx{varMap: jet.VarMap{}}
}
// Get returns the value for a key in the embedded jet.VarMap.
// The returned reflect.Value is not valid if the key does not exist.
func (scope *VarMapMx) Get(name string) reflect.Value {
v, _ := scope.Lookup(name)
return v
}
// Lookup returns the value for a key in the embedded jet.VarMap
// as well as whether the key was found or not.
func (scope *VarMapMx) Lookup(name string) (reflect.Value, bool) {
scope.mx.RLock()
defer scope.mx.RUnlock()
v, ok := scope.varMap[name]
return v, ok
}
// Set adds the key value pair in the embedded jet.VarMap.
func (scope *VarMapMx) Set(name string, v interface{}) *VarMapMx {
scope.mx.Lock()
defer scope.mx.Unlock()
scope.varMap.Set(name, v)
return scope
}
// SetFunc adds a jet.Func to the embedded jet.VarMap.
func (scope *VarMapMx) SetFunc(name string, v jet.Func) *VarMapMx {
scope.mx.Lock()
defer scope.mx.Unlock()
scope.varMap.Set(name, v)
return scope
}
// SetWriter adds a jet.SafeWriter to the embedded jet.VarMap.
func (scope *VarMapMx) SetWriter(name string, v jet.SafeWriter) *VarMapMx {
scope.mx.Lock()
defer scope.mx.Unlock()
scope.varMap.Set(name, v)
return scope
}
// GetVarMap returns the embedded jet.VarMap for use in template executions.
func (scope *VarMapMx) GetVarMap() jet.VarMap {
return scope.varMap
}
使用如下:
vars := NewVarMapMx()
vars.Set("user", &User{}).Set("userID", "1234")
if err = t.Execute(&w, vars.GetVarMap(), nil); err != nil {
// error when executing template
}
最后一个参数是上下文,Jet允许使用任意对象作为上下文,并使用.
在模板中访问上下文内容。例如:
<form action="/user" method="post">
<input name="firstname" value="{{ .Firstname }}" />
</form>
模板中的块在复用是也可以滴啊用上下文,他们在模板中进行传递并保持不变。