Gin框架模板怎么实现树形菜单递归渲染

阿辰小哥_4647

阿辰小哥_4647

2026-10-13

592人浏览

原创

go的html/template不支持递归,需用{{define "name"}}定义命名模板并显式传参调用,且必须顶层定义、统一字段名、避免循环引用、控制层级深度、确保模板加载正确。

gin框架模板怎么实现树形菜单递归渲染

Go 的 html/template 本身不支持递归,但可以安全模拟

直接写 {{template "menu-item" .}} 在自身模板里会 panic,因为 Go 模板引擎禁止无限递归调用。必须用 {{define "menu-item"}} 显式定义一个命名模板,再通过 {{template "menu-item" .Children}} 显式传参调用——这不是语法糖,而是唯一能控制终止条件的安全方式。

常见错误现象:模板里漏掉 {{if .Children}} 判断,导致空切片仍触发一次 {{template}} 调用,渲染出多余 <ul></ul> 或 panic;或者把 {{define}} 写在 {{range}} 里面,结果只在当前作用域生效,递归时找不到模板。

  • 必须将 {{define "menu-item"}} 放在顶层(不能嵌套在 {{range}} 或 {{with}} 中)
  • 每次递归都需显式传入子节点,如 {{template "menu-item" .Children}},不能依赖当前 .
  • 子节点字段名要统一,比如后端 struct 定义为 Children []MenuItem,模板里就固定用 .Children

后端数据结构必须提前扁平化或严格避免循环引用

如果菜单数据是嵌套 struct,比如 type MenuItem struct { Name string; Children []MenuItem; Parent *MenuItem },模板渲染时可能因 Parent 字段形成循环引用,在 json.Marshal 或深度遍历时直接 panic。

推荐做法是:在 Gin handler 中就完成树形构建,传给模板的是纯值类型切片,例如 []MenuItem,而不是 []*MenuItem —— 后者一旦某个 Children 元素为 nil,模板执行就会失败。

  • 用父 ID 扁平化数据 + 服务端递归组装,比前端 JS 处理更可控
  • 层级过深(>6 层)时,模板递归容易触发 goroutine stack overflow,建议后端只传前 3–4 层,深层靠前端展开逻辑
  • URL、图标、是否激活等展示字段,务必在 handler 中补全,不要在模板里用 if 做业务判断

{{template}} 调用时容器标签必须包裹在条件判断内

单纯用 {{range .Children}} 渲染子菜单很危险:当 .Children 是空切片时,{{range}} 内部完全不执行,但你通常仍需要一个空的 <ul></ul> 容器来维持 CSS 样式或 JS 行为。

Gin框架 1.9.0
Gin框架 1.9.0

Gin框架 1.9.0版本源码包下载,版本号 1.9.0,适合需要 sonic JSON 支持、路由修复和内容协商改进的 Go Web 开发场景。

下载

正确写法是先判断是否存在子项,再决定是否渲染容器和内容:

{{if .Children}}
{{end}}

但更推荐把整个子菜单逻辑封装进 {{define "menu-item"}},并在其中统一处理容器与递归调用:

{{define "menu-item"}}
  • {{.Name}} {{if .Children}}
      {{range .Children}} {{template "menu-item" .}} {{end}}
    {{end}}
  • {{end}}

    Gin 加载模板时路径和命名必须匹配 glob 规则

    如果模板文件放在 templates/layout/menu.tmpl,而你用 r.LoadHTMLGlob("templates/*.tmpl"),那这个文件根本不会被加载,{{template "menu-item"}} 会报错 template: menu-item is undefined。

    实际中容易忽略两点:一是 LoadHTMLGlob 的 glob 模式必须覆盖所有模板文件路径;二是局部模板名({{define "xxx"}})和 {{template "xxx"}} 中的字符串必须完全一致,大小写敏感,且不能带文件扩展名。

    • 推荐统一用 r.LoadHTMLGlob("templates/**/*"),确保子目录下所有 .tmpl 或 .html 都被加载
    • 局部模板名建议用语义化短名,如 "menu-item"、"nav-link",避免带路径或版本号
    • 调试时可加 log.Println("loaded templates:", template.Templates()) 查看已注册模板列表
    实际递归最易卡住的地方不在语法,而在数据结构是否干净、层级是否可控、以及模板名是否真被加载进引擎——这三处任一出错,都会静默失败或 panic,且错误信息不指向真实原因。

    相关文章

    PHP速学视频免费教程(入门到精通)
    PHP速学视频免费教程(入门到精通)

    PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

    下载

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

    相关专题

    更多
    Golang Beego框架
    Golang Beego框架

    本专题聚焦 Golang 全栈式 Web 框架 Beego 的学习与实战,内容涵盖 MVC 模式、路由控制、ORM 数据库操作、模块化开发、日志管理与 RESTful API 构建。通过企业管理系统、电商后端与微服务架构等实战案例,帮助学员掌握使用 Beego 高效开发企业级应用的核心能力。

    2025.08.27

    3220

    8

    go语言 beego框架
    go语言 beego框架

    本专题整合了go语言中beego框架相关内容,阅读专题下的文章了解更多详细内容。

    2025.09.10

    6521

    12

    Go Web框架Gin接口开发与中间件设计实践
    Go Web框架Gin接口开发与中间件设计实践

    本专题围绕 Go 在 Web 后端开发中的主流框架 Gin 展开,系统讲解高性能接口开发与中间件机制设计。内容涵盖路由分组、请求绑定、参数校验、统一响应封装、日志与鉴权中间件实现,以及接口限流与异常处理策略。通过实战项目案例,帮助开发者构建结构清晰、性能优良的 Go Web 服务体系,提升接口开发效率与系统可维护性。

    2026.03.19

    317

    21

    PixTV官网入口地址合集
    PixTV官网入口地址合集

    本专题汇总了 PixTV AI 一站式视频创作平台的官方入口与使用教程。无需下载软件,浏览器直接访问即可使用。平台将剧本、图像、视频、声音与剪辑整合在“无限画布”中,接入 GPT Image 2.5、Seedance 2.5 等头部模型。本专题整理了从新建画布、角色锚定、分镜拆分到视频生成与导出的完整操作指南,助你快速上手 AI 短剧与漫剧创作。

    2026.10.10

    40

    15

    Kratos框架HTTP与gRPC服务开发教程
    Kratos框架HTTP与gRPC服务开发教程

    本专题围绕Kratos框架双协议服务开发,涵盖HTTP路由与处理器编写、参数获取、gRPC服务实现与客户端调用、metadata上下文传递、encoding编解码注册、统一响应封装、超时控制与流式响应实现方法。

    2026.10.10

    20

    15

    Kratos框架Protobuf接口定义与代码生成合集
    Kratos框架Protobuf接口定义与代码生成合集

    本专题讲解Kratos框架接口定义体系,涵盖proto编写规范、proto add/client/server生成命令、http注解路由、validate校验、OpenAPI文档生成、跨服务proto复用与兼容性设计。

    2026.10.10

    0

    15

    C++虚函数怎么定义和调用
    C++虚函数怎么定义和调用

    C++虚函数是实现运行时多态的重要机制。本专题从virtual关键字的基本用法入手,介绍基类与派生类之间的函数重写、基类指针调用派生类方法,以及动态绑定的执行过程,帮助初学者掌握虚函数的核心语法。

    2026.10.10

    20

    26

    C++类与对象的封装方法教程
    C++类与对象的封装方法教程

    C++封装是面向对象编程的核心特性之一,通过类将数据与操作数据的函数组织在一起,并利用访问权限控制外部访问。本专题介绍类的定义、成员变量、成员函数以及public、private和protected的使用方法,帮助初学者掌握封装的基本原理。

    2026.10.10

    20

    32

    C++构造函数定义与调用方法
    C++构造函数定义与调用方法

    C++构造函数用于初始化类对象,是面向对象编程的重要基础。本专题从构造函数的定义、声明和调用入手,介绍默认构造函数、带参数构造函数、拷贝构造函数及成员初始化列表,帮助初学者掌握对象创建与初始化的基本方法。

    2026.10.10

    20

    16

    热门下载

    更多
    网站特效
    /
    网站源码
    /
    网站素材
    /
    前端模板

    精品课程

    更多
    相关推荐
    /
    热门推荐
    /
    最新课程
    Gin框架快速入门指南
    Gin框架快速入门指南

    共0课时 | 0人学习

    Gin框架官方中文文档
    Gin框架官方中文文档

    共0课时 | 0人学习

    Go语言Gin框架全套实战教程
    Go语言Gin框架全套实战教程

    共0课时 | 0人学习