
Go 模板中,使用 {{template}} 调用 {{define}} 定义的子模板时,默认不继承父模板的数据上下文;必须显式通过 .(当前数据)或具体字段(如 .tes)传入,否则子模板无法访问变量。
go 模板中,使用 `{{template}}` 调用 `{{define}}` 定义的子模板时,默认不继承父模板的数据上下文;必须显式通过 `.`(当前数据)或具体字段(如 `.tes`)传入,否则子模板无法访问变量。
在 Go 的 html/template 包中,{{define}} 定义的命名模板(如 "contents")是作用域隔离的:它不会自动接收外层模板(如 layout.html)所执行的数据上下文(.title、.tes 等)。当你写 {{template "contents"}} 时,Go 实际上传入的是一个空的、未初始化的 interface{}——即子模板内部的 . 为 nil,因此 {{.tes}} 渲染为空,导致 <script> 中的 var x = ; 语法错误,console.log(x) 自然不会执行。</script>
✅ 正确做法:在 layout.html 中显式传递上下文:
<!-- page/layout.html -->
{{template "contents" .}} <!-- 传递整个 Data 映射 -->
这样,index.html 中的 {{.tes}} 就能正常解析为 JSON 字符串(如 {"item":"TEST3","count":4567}),最终生成合法 JavaScript:
<script>
var x = {"item":"TEST3","count":4567};
console.log(x); // ✅ 正常输出
</script>
⚠️ 注意事项:
- M.ToJSON(tes) 应确保返回 安全的 JSON 字符串(不含 HTML 转义),否则需配合 template.JS 类型或 {{. | safeJS}}(需自定义函数)防止 XSS 或解析失败;
- 若仅需子模板访问特定字段(如仅 .tes),可更精确地传递:{{template "contents" .tes}},此时子模板内 . 直接等于该 map 值,可直接写 {{.item}} 或 {{.count}};
- 模板解析顺序无关文件先后,但 ParseFiles 中 layout.html 在前、index.html 在后是常规做法(确保 define 已注册);
- 使用 template.Must() 可提前捕获解析错误,提升开发体验。
完整修复后的 layout.html 片段如下:
<!-- page/layout.html -->
<meta charset="UTF-8"><title>{{.title}} | {{.project_name}}</title><div id="wrapper">
{{template "contents" .}} <!-- 关键:显式传参 -->
</div>
此举既保持了布局与内容的解耦,又确保了数据流清晰可控——这是构建可维护 Go Web 模板系统的核心实践之一。











