Golang HTML 模板使用指南示例詳解
更新時間:2025年01月14日 09:30:44 作者:老大白菜
本文詳細(xì)介紹了Golang HTML模板的使用方法,包括基礎(chǔ)模板、高級模板、完整應(yīng)用示例、CSS樣式、JavaScript交互等,文章強調(diào)了模板組織、代碼復(fù)用、語義化HTML、響應(yīng)式設(shè)計、性能優(yōu)化等最佳實踐,感興趣的朋友跟隨小編一起看看吧
Golang HTML 模板使用指南
1. 基礎(chǔ)模板示例
1.1 簡單頁面模板
<!-- templates/layout.html -->
<!DOCTYPE html>
<html>
<head>
<title>{{.Title}}</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/static/css/style.css" rel="external nofollow" >
</head>
<body>
<header>
<h1>{{.Title}}</h1>
<nav>
<a href="/" rel="external nofollow" >首頁</a>
<a href="/about" rel="external nofollow" >關(guān)于</a>
<a href="/contact" rel="external nofollow" >聯(lián)系我們</a>
</nav>
</header>
<main>
{{template "content" .}}
</main>
<footer>
<p>© {{.Year}} 我的網(wǎng)站</p>
</footer>
</body>
</html>// main.go
package main
import (
"html/template"
"net/http"
"time"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(template.ParseFiles("templates/layout.html"))
data := struct {
Title string
Year int
}{
Title: "我的網(wǎng)站",
Year: time.Now().Year(),
}
tmpl.Execute(w, data)
})
http.ListenAndServe(":8080", nil)
}1.2 列表渲染
<!-- templates/products.html -->
{{define "content"}}
<div class="products">
<h2>產(chǎn)品列表</h2>
<div class="product-grid">
{{range .Products}}
<div class="product-card">
<img src="{{.Image}}" alt="{{.Name}}">
<h3>{{.Name}}</h3>
<p>{{.Description}}</p>
<div class="price">{{formatPrice .Price}}</div>
{{if .InStock}}
<button class="buy-btn">購買</button>
{{else}}
<button class="out-of-stock" disabled>缺貨</button>
{{end}}
</div>
{{end}}
</div>
</div>
{{end}}type Product struct {
Name string
Description string
Price float64
Image string
InStock bool
}
func productsHandler(w http.ResponseWriter, r *http.Request) {
funcMap := template.FuncMap{
"formatPrice": func(price float64) string {
return fmt.Sprintf("¥%.2f", price)
},
}
tmpl := template.New("layout.html").Funcs(funcMap)
tmpl = template.Must(tmpl.ParseFiles(
"templates/layout.html",
"templates/products.html",
))
data := struct {
Title string
Year int
Products []Product
}{
Title: "產(chǎn)品列表",
Year: time.Now().Year(),
Products: []Product{
{
Name: "商品1",
Description: "這是商品1的描述",
Price: 99.99,
Image: "/static/images/product1.jpg",
InStock: true,
},
// 更多商品...
},
}
tmpl.Execute(w, data)
}2. 高級模板示例
2.1 嵌套模板
<!-- templates/components/header.html -->
{{define "header"}}
<header class="site-header">
<div class="logo">
<img src="/static/images/logo.png" alt="Logo">
</div>
<nav class="main-nav">
<ul>
{{range .NavItems}}
<li class="{{if eq $.CurrentPage .Link}}active{{end}}">
<a href="{{.Link}}" rel="external nofollow" >{{.Text}}</a>
</li>
{{end}}
</ul>
</nav>
{{if .User}}
<div class="user-menu">
<span>歡迎, {{.User.Name}}</span>
<a href="/logout" rel="external nofollow" >退出</a>
</div>
{{else}}
<div class="auth-buttons">
<a href="/login" rel="external nofollow" class="btn btn-login">登錄</a>
<a href="/register" rel="external nofollow" class="btn btn-register">注冊</a>
</div>
{{end}}
</header>
{{end}}2.2 表單處理
<!-- templates/form.html -->
{{define "content"}}
<div class="form-container">
<h2>{{.FormTitle}}</h2>
{{with .FormError}}
<div class="error-message">{{.}}</div>
{{end}}
<form method="POST" action="{{.FormAction}}" enctype="multipart/form-data">
{{range .Fields}}
<div class="form-group">
<label for="{{.ID}}">{{.Label}}{{if .Required}}*{{end}}</label>
{{if eq .Type "text"}}
<input type="text" id="{{.ID}}" name="{{.Name}}"
value="{{.Value}}" {{if .Required}}required{{end}}
{{with .Pattern}}pattern="{{.}}"{{end}}>
{{else if eq .Type "textarea"}}
<textarea id="{{.ID}}" name="{{.Name}}"
{{if .Required}}required{{end}}>{{.Value}}</textarea>
{{else if eq .Type "select"}}
<select id="{{.ID}}" name="{{.Name}}"
{{if .Required}}required{{end}}>
{{range .Options}}
<option value="{{.Value}}" {{if eq .Value $.Selected}}selected{{end}}>
{{.Text}}
</option>
{{end}}
</select>
{{end}}
{{with .Error}}
<span class="field-error">{{.}}</span>
{{end}}
</div>
{{end}}
<div class="form-actions">
<button type="submit" class="btn btn-primary">{{.SubmitText}}</button>
<button type="reset" class="btn btn-secondary">重置</button>
</div>
</form>
</div>
{{end}}2.3 分頁組件
<!-- templates/components/pagination.html -->
{{define "pagination"}}
<div class="pagination">
{{if gt .TotalPages 1}}
{{if gt .CurrentPage 1}}
<a href="?page=1" rel="external nofollow" class="page-link first">«</a>
<a href="?page={{subtract .CurrentPage 1}}" rel="external nofollow" class="page-link prev">‹</a>
{{end}}
{{range $i := range (sequence .TotalPages)}}
{{if and (ge $i (subtract $.CurrentPage 2)) (le $i (add $.CurrentPage 2))}}
<a href="?page={{add $i 1}}" rel="external nofollow"
class="page-link {{if eq $i (subtract $.CurrentPage 1)}}active{{end}}">
{{add $i 1}}
</a>
{{end}}
{{end}}
{{if lt .CurrentPage .TotalPages}}
<a href="?page={{add .CurrentPage 1}}" rel="external nofollow" class="page-link next">›</a>
<a href="?page={{.TotalPages}}" rel="external nofollow" class="page-link last">»</a>
{{end}}
{{end}}
</div>
{{end}}3. 完整應(yīng)用示例
3.1 博客系統(tǒng)模板
<!-- templates/blog/list.html -->
{{define "content"}}
<div class="blog-list">
<div class="filters">
<div class="search">
<input type="text" placeholder="搜索文章..."
value="{{.Query}}" id="searchInput">
</div>
<div class="categories">
{{range .Categories}}
<a href="/blog?category={{.Slug}}" rel="external nofollow"
class="category {{if eq $.CurrentCategory .Slug}}active{{end}}">
{{.Name}} ({{.Count}})
</a>
{{end}}
</div>
</div>
<div class="articles">
{{range .Posts}}
<article class="post-card">
{{if .Image}}
<div class="post-image">
<img src="{{.Image}}" alt="{{.Title}}">
</div>
{{end}}
<div class="post-content">
<h2><a href="/blog/{{.Slug}}" rel="external nofollow" >{{.Title}}</a></h2>
<div class="post-meta">
<span class="author">{{.Author}}</span>
<span class="date">{{formatDate .CreatedAt "2006-01-02"}}</span>
<span class="category">{{.Category}}</span>
</div>
<p class="excerpt">{{truncate .Content 200}}</p>
<div class="tags">
{{range .Tags}}
<a href="/blog?tag={{.}}" rel="external nofollow" class="tag">{{.}}</a>
{{end}}
</div>
</div>
</article>
{{else}}
<div class="no-posts">
暫無文章
</div>
{{end}}
</div>
{{template "pagination" .Pagination}}
</div>
{{end}}type BlogData struct {
Query string
CurrentCategory string
Categories []Category
Posts []Post
Pagination Pagination
}
type Category struct {
Name string
Slug string
Count int
}
type Post struct {
Title string
Slug string
Content string
Author string
Image string
Category string
Tags []string
CreatedAt time.Time
}
type Pagination struct {
CurrentPage int
TotalPages int
TotalItems int
}
func blogHandler(w http.ResponseWriter, r *http.Request) {
funcMap := template.FuncMap{
"formatDate": func(t time.Time, layout string) string {
return t.Format(layout)
},
"truncate": func(s string, l int) string {
if len(s) <= l {
return s
}
return s[:l] + "..."
},
}
tmpl := template.New("layout.html").Funcs(funcMap)
tmpl = template.Must(tmpl.ParseFiles(
"templates/layout.html",
"templates/blog/list.html",
"templates/components/pagination.html",
))
data := BlogData{
Query: r.URL.Query().Get("q"),
CurrentCategory: r.URL.Query().Get("category"),
Categories: []Category{
{Name: "技術(shù)", Slug: "tech", Count: 10},
{Name: "生活", Slug: "life", Count: 5},
},
Posts: []Post{
{
Title: "示例文章",
Slug: "example-post",
Content: "這是一篇示例文章的內(nèi)容...",
Author: "作者名",
Category: "tech",
Tags: []string{"Go", "Web"},
CreatedAt: time.Now(),
},
},
Pagination: Pagination{
CurrentPage: 1,
TotalPages: 5,
TotalItems: 45,
},
}
tmpl.Execute(w, data)
}4. CSS 樣式示例
/* static/css/style.css */
/* 基礎(chǔ)樣式 */
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
line-height: 1.6;
margin: 0;
padding: 0;
color: #333;
}
/* 頭部樣式 */
.site-header {
background: #fff;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
padding: 1rem;
}
.main-nav ul {
list-style: none;
display: flex;
gap: 1rem;
}
/* 產(chǎn)品卡片樣式 */
.product-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 2rem;
padding: 2rem;
}
.product-card {
border: 1px solid #eee;
border-radius: 8px;
overflow: hidden;
transition: transform 0.2s;
}
.product-card:hover {
transform: translateY(-5px);
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}
/* 表單樣式 */
.form-container {
max-width: 600px;
margin: 2rem auto;
padding: 2rem;
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.form-group {
margin-bottom: 1.5rem;
}
/* 博客列表樣式 */
.blog-list {
max-width: 1200px;
margin: 0 auto;
padding: 2rem;
}
.post-card {
display: grid;
grid-template-columns: 200px 1fr;
gap: 1.5rem;
margin-bottom: 2rem;
padding: 1rem;
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
/* 分頁樣式 */
.pagination {
display: flex;
justify-content: center;
gap: 0.5rem;
margin: 2rem 0;
}
.page-link {
padding: 0.5rem 1rem;
border: 1px solid #ddd;
border-radius: 4px;
color: #333;
text-decoration: none;
}
.page-link.active {
background: #007bff;
color: #fff;
border-color: #007bff;
}5. JavaScript 交互示例
// static/js/main.js
document.addEventListener('DOMContentLoaded', function() {
// 搜索功能
const searchInput = document.getElementById('searchInput');
if (searchInput) {
searchInput.addEventListener('input', debounce(function(e) {
const query = e.target.value;
window.location.href = `/blog?q=${encodeURIComponent(query)}`;
}, 500));
}
// 表單驗證
const forms = document.querySelectorAll('form');
forms.forEach(form => {
form.addEventListener('submit', function(e) {
const requiredFields = form.querySelectorAll('[required]');
let valid = true;
requiredFields.forEach(field => {
if (!field.value.trim()) {
valid = false;
field.classList.add('error');
} else {
field.classList.remove('error');
}
});
if (!valid) {
e.preventDefault();
alert('請?zhí)顚懰斜靥钭侄?);
}
});
});
});
// 工具函數(shù)
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}總結(jié)
模板組織
- 使用嵌套模板實現(xiàn)代碼復(fù)用
- 保持模板結(jié)構(gòu)清晰
- 合理使用模板函數(shù)
最佳實踐
- 使用語義化 HTML
- 保持 CSS 模塊化
- 實現(xiàn)響應(yīng)式設(shè)計
- 添加適當(dāng)?shù)慕换バЧ?/li>
性能優(yōu)化
- 緩存編譯后的模板
- 壓縮靜態(tài)資源
- 使用 CDN 加速
- 實現(xiàn)懶加載
到此這篇關(guān)于Golang HTML 模板使用指南的文章就介紹到這了,更多相關(guān)Golang HTML 模板內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
golang包循環(huán)引用的幾種解決方案總結(jié)
golang有包循環(huán)引用問題,用過的應(yīng)該都知道,下面這篇文章主要給大家介紹了關(guān)于golang包循環(huán)引用的幾種解決方案,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-09-09
簡化Go開發(fā)提高生產(chǎn)力的強大工具及使用詳解
作為?Go?開發(fā)人員,應(yīng)該都知道維持簡潔高效開發(fā)工作流程的重要性,為了提高工作效率和代碼質(zhì)量,簡化開發(fā)流程并自動執(zhí)行重復(fù)性任務(wù)至關(guān)重要,在本文中,我們將探討一些強大的工具和技術(shù),它們將簡化?Go?開發(fā)過程,助力您的編碼之旅2023-10-10
5個可以在Golang中優(yōu)化代碼以提高性能的技巧分享
作為一名軟件工程師,確保你的代碼高效且性能良好是非常重要的。本文主要和大家分享5個可以在Golang中優(yōu)化代碼以提高性能的技巧,希望對大家有所幫助2023-03-03
Golang實現(xiàn)Java虛擬機之解析class文件詳解
這篇文章主要為大家詳細(xì)介紹了Golang實現(xiàn)Java虛擬機之解析class文件的相關(guān)知識,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-01-01
Golang Printf,Sprintf,Fprintf 格式化詳解
這篇文章主要介紹了Golang Printf,Sprintf,Fprintf 格式化詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-03-03

