Golang Template include 嵌套子模版时的变量重命名

文章目录

    Golang Template 开发网页时遇到一个模版内变量命名的问题。

    问题

    多个不同页面需要使用同一个子模版,比如推荐产品列表这个子模版,需要在产品列表页、首页、404页面、搜索页面等多个页面使用该子模版。

    子模版目前是这样定义的, product_cards.html:

    {{ range .Items }}
    <div class="product-card">
    	<a href="{{ .URL }}" class="block">
    		<h3 class="product-name">{{ .Name }}</h3>
    	</a>
    </div>
    {{ else }}
    <p class="text-gray">No products found.</p>
    {{ end }}
    

    其他页面引用子模版:

    {{ template "product_cards.html" . }}
    

    看起来没啥问题,但是当多个页面引用同一个子模版时,就会出现变量名歧义的问题。
    例如,产品页使用 Items 没啥问题,很好理解,Items 是产品列表。
    但是在首页使用这个子模版时,Items 这个名字就不太合适了,因为首页还有其他的展示区域,Items 这个名字就不够具体。

    golang template 文档

    https://pkg.go.dev/text/template

    官方文档,真的一言难尽,又枯燥又抽象。我也没有找到什么具体的例子来说明这个问题。

    Google 了半天,也没有找到类似的问题讨论。
    因为我也不知道该怎么描述这个问题。。。

    {{ template "product_cards.html" . }}
    

    这种语法到底应该叫子模版,还是嵌套模版,还是其他什么名字?我知道 PHP Laravel 里叫 include 语法。
    但是 golang 这里 template 关键词跟功能名称一样就更没法描述了 😅

    {{template "name"}}
    	The template with the specified name is executed with nil data.
    
    {{template "name" pipeline}}
    	The template with the specified name is executed with dot set
    	to the value of the pipeline.
    

    今天抽时间把这个官方文档再读一遍,整理出来看不懂的概念,例如 pipeline,问问 AI 比较好。

    最后还是得靠 DeepSeek 才能搞定。

    子模版内部重新赋值

    DeepSeek 给出的方案是:

    父模板中直接使用对应的变量名传递给子模板,例如:

    {{ template "product_cards.html" .Products }}
    

    子模版内部重新赋值一个变量名

    {{ $items := . }}
    {{ range $index, $item := $items }}
      <div>{{ $item.Name }}</div>
    {{ end }}
    

    或者

    {{ $items := . }}
    {{ range $items }}
      <div>{{ .Name }}</div>
    {{ end }}
    

    感觉还是第一种方式可读性更好一些。到处是 . 很不好理解。

    子模版中的 . 代表父模板传递过来的数据,可以直接赋值给一个新的变量名 $items,然后在子模版内部使用 $items 来进行遍历和操作。

    到此,问题完美解决。

    golang template 中的变量

    https://docs.gofiber.io/template/html/TEMPLATES_CHEATSHEET/#template-variables

    gofiber 的文档倒是比 go 官方文档好一些,里面有专门示例说明:

    总结一下,就是:

    golang 传递给模板的数据,是通过 . 来访问的:

    • 如果传递的是 map,则可以通过 .Key 来访问对应的值
    • 如果传递的是整形/字符串等基本类型,则直接使用 .
    • 如果是父模板传递给子模板的数据,则同样使用 . 来处理

    同时,可以在模板内部定义变量,使用

    {{$number := .}}
    <h1> It is day number {{$number}} of the month </h1>
    

    语法来定义变量,然后通过 $xxx 来访问变量的值。

    有必要单独整理一个文档来项目列举各种使用场景。

    关于作者 🌱

    我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊,或者关注我的个人公众号“大象工具”, 查看更多联系方式