Golang http/template中$active变量无法控制导航栏激活状态问题
这个问题我之前也踩过坑——Go的http/template是按模板执行顺序处理变量的,你引入的头部模板会在主体模板的变量定义前就渲染完成,所以主体里定义的$active根本没办法影响到头部的导航逻辑。下面给你几个实用的解决思路:
方法1:在Execute时直接传入Active变量
这是最直接的方案,把激活状态作为模板数据的一部分,在调用Execute的时候传进去,让头部模板直接读取这个变量。
首先定义模板数据结构(用map也可以):
type PageData struct { ActiveNav string // 标记当前激活的导航项 // 其他页面需要的字段... }
在处理请求时,给当前页面设置对应的激活值:
func siteTesterHandler(w http.ResponseWriter, r *http.Request) { data := PageData{ ActiveNav: "SiteTester", // 对应导航项的名称 } // 假设已解析好模板 err := tmpl.Execute(w, data) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } }
修改头部模板,直接用$.ActiveNav判断:
{{ $a := mkSlice "SiteTester" "/sitetester-add/" }} {{ $b := mkSlice "Index" "/" }} {{ $nav := mkSlice $a $b }} {{ range $item := $nav }} <a href="{{ index $item 1 }}" class="{{ if eq $.ActiveNav (index $item 0) }}active{{ end }}"> {{ index $item 0 }} </a> {{ end }}
方法2:通过自定义上下文传递变量给头部模板
如果不想每次修改Execute的传入数据,或者需要在主体模板里动态设置激活状态,可以用字典合并的方式,把自定义变量加到模板上下文中再传给头部。
首先注册一个合并map的模板函数(Go模板默认没有这个函数):
func mergeContext(a, b map[string]interface{}) map[string]interface{} { merged := make(map[string]interface{}) // 拷贝原有上下文 for k, v := range a { merged[k] = v } // 加入新变量 for k, v := range b { merged[k] = v } return merged } // 注册到模板FuncMap funcMap := template.FuncMap{ "merge": mergeContext, } tmpl := template.Must(template.New("").Funcs(funcMap).ParseFiles("header.tmpl", "body.tmpl"))
在主体模板里,先定义$active,再把合并后的上下文传给头部:
{{ $active := "SiteTester" }} {{ template "header" (merge . (dict "Active" $active)) }} <!-- 主体内容 -->
头部模板用$.Active判断激活状态:
{{ range $item := $nav }} <a href="{{ index $item 1 }}" class="{{ if eq $.Active (index $item 0) }}active{{ end }}"> {{ index $item 0 }} </a> {{ end }}
方法3:基于当前请求路径自动判断(更省心)
如果导航激活状态和当前URL路径对应,完全不用手动设置$active,通过模板函数获取当前请求路径自动匹配即可。
首先注册一个获取当前路径的模板函数:
funcMap := template.FuncMap{ "currentPath": func(r *http.Request) string { return r.URL.Path }, }
处理请求时,把*http.Request传到模板数据里:
func siteTesterHandler(w http.ResponseWriter, r *http.Request) { data := map[string]interface{}{ "Request": r, // 其他数据... } err := tmpl.Execute(w, data) // 错误处理... }
头部模板直接对比路径:
{{ range $item := $nav }} <a href="{{ index $item 1 }}" class="{{ if eq (currentPath $.Request) (index $item 1) }}active{{ end }}"> {{ index $item 0 }} </a> {{ end }}
这种方式一劳永逸,不需要每个页面手动设置激活项,适合大多数场景。
内容的提问来源于stack exchange,提问作者Steve B
相关产品推荐
相关产品推荐

