Подробное руководство по define, template и block в html/template
В пакете html/template есть три основные директивы для работы с повторно используемыми частями шаблонов: define, template, block
Основные концепции
В пакете html/template
есть три основные директивы для работы с повторно используемыми частями шаблонов:
{{define "name"}}...{{end}}
- определяет именованный шаблон{{template "name"}}
- вставляет именованный шаблон{{block "name"}}...{{end}}
- комбинация define+template с возможностью переопределения
1. Директива define
Где описывать:
- В любом месте шаблона (но обычно в начале или конце файла)
- В отдельных файлах, которые потом объединяются
Пример определения:
{{define "header"}}
<header>
<h1>{{.Title}}</h1>
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
</nav>
</header>
{{end}}
{{define "footer"}}
<footer>
<p>Copyright © {{.Year}} My Company</p>
</footer>
{{end}}
2. Директива template
Где применять:
- В любом месте основного шаблона
- Можно передавать данные (по умолчанию - текущий контекст)
Пример использования:
<!DOCTYPE html>
<html>
<head>
<title>{{.Title}}</title>
</head>
<body>
{{template "header" .}} <!-- Передаем текущий контекст -->
<main>
{{.Content}}
</main>
{{template "footer" .}} <!-- Передаем текущий контекст -->
</body>
</html>
Передача другого контекста:
{{template "user_profile" .UserData}}
3. Директива block
Особенности:
- Комбинация
define
+template
- Можно переопределять в дочерних шаблонах
- Если не переопределен - используется содержимое по умолчанию
Пример:
<!-- base.html -->
<!DOCTYPE html>
<html>
<head>
{{block "head" .}}
<title>{{.Title}} - Default</title>
{{end}}
</head>
<body>
{{block "content" .}}
<p>Default content</p>
{{end}}
</body>
</html>
Переопределение в дочернем шаблоне:
<!-- home.html -->
{{define "content"}}
<h1>Welcome!</h1>
<p>This is the home page.</p>
{{end}}
{{template "base.html" .}}
Практические схемы организации
1. Многофайловая структура
$$templates/
├── base.html # Основной каркас
├── header.html # Шапка сайта
├── footer.html # Подвал
├── home.html # Главная страница
└── about.html # Страница "О нас"$$
base.html:
<!DOCTYPE html>
<html>
<head>
{{template "head" .}}
</head>
<body>
{{template "header" .}}
{{block "content" .}}{{end}}
{{template "footer" .}}
</body>
</html>
home.html:
{{define "content"}}
<h1>Welcome</h1>
<p>Home page content</p>
{{end}}
{{template "base.html" .}}
2. Наследование шаблонов
// Загрузка шаблонов
templates := template.Must(template.ParseFiles(
"base.html",
"header.html",
"footer.html",
"home.html",
))
// Исполнение конкретного шаблона
err := templates.ExecuteTemplate(w, "home.html", data)
3. Вложенные блоки
<!-- base.html -->
{{define "layout"}}
<div class="container">
{{block "sidebar" .}}
<!-- Default sidebar -->
<div class="sidebar">Default sidebar</div>
{{end}}
<div class="content">
{{template "content" .}}
</div>
</div>
{{end}}
<!-- profile.html -->
{{define "sidebar"}}
<div class="profile-sidebar">
<img src="{{.User.Avatar}}">
<h3>{{.User.Name}}</h3>
</div>
{{end}}
{{define "content"}}
<div class="profile-content">
<!-- Контент профиля -->
</div>
{{end}}
{{template "layout" .}}
Особенности работы
- Порядок загрузки: шаблоны, на которые есть ссылки, должны быть загружены до их использования
- Контекст данных: по умолчанию передается текущий контекст, но можно передать другой
- Рекурсия: шаблоны могут вызывать сами себя (но осторожно с бесконечной рекурсией)
- Переопределение: последний загруженный шаблон с тем же именем переопределяет предыдущий
Пример с пользовательскими функциями
func main() {
funcMap := template.FuncMap{
"formatDate": func(t time.Time) string {
return t.Format("2006-01-02")
},
}
tmpl := template.Must(
template.New("base").Funcs(funcMap).ParseFiles("base.html", "home.html"),
)
err := tmpl.ExecuteTemplate(os.Stdout, "home.html", data)
}
<!-- В шаблоне: -->
<p>Created: {{.CreatedAt | formatDate}}</p>
Лучшие практики
- Разделяйте шаблоны на логические компоненты
- Используйте
block
для переопределяемых секций - Основной каркас выносите в
base.html
- Называйте шаблоны осмысленно (не “template1”, а “user_profile”)
- Документируйте назначение шаблонов в комментариях