Có thể có các mẫu lồng nhau trong Go bằng thư viện chuẩn không?


87

Làm cách nào để lấy các mẫu lồng nhau như Jinja có trong thời gian chạy python. Ý tôi là TBC là làm thế nào để tôi có một loạt các mẫu kế thừa từ các mẫu cơ sở, chỉ cần lưu trữ trong các khối của các mẫu cơ sở, giống như Jinja / django-templates. Có thể sử dụng chỉ html/templatetrong thư viện tiêu chuẩn.

Nếu đó không phải là một khả năng, thì lựa chọn thay thế của tôi là gì. Bộ ria mép dường như là một lựa chọn nhưng liệu tôi có bỏ lỡ những tính năng tinh tế tuyệt vời html/templatenhư thoát ngữ cảnh nhạy cảm, v.v. không? Những lựa chọn thay thế nào khác là nhiệt?

(Môi trường: Google App Engin, Go runtime v1, Dev - Mac OSx lion)

Cảm ơn vì đã đọc.

Câu trả lời:


132

Có nó là có thể. A html.Templatethực sự là một tập hợp các tệp mẫu. Nếu bạn thực thi một khối đã xác định trong tập hợp này, nó có quyền truy cập vào tất cả các khối khác được xác định trong tập hợp này.

Nếu bạn tự mình tạo một bản đồ gồm các bộ mẫu như vậy, về cơ bản bạn có tính linh hoạt giống như Jinja / Django cung cấp. Sự khác biệt duy nhất là gói html / template không có quyền truy cập trực tiếp vào hệ thống tệp, vì vậy bạn phải phân tích cú pháp và soạn các mẫu theo ý mình.

Hãy xem xét ví dụ sau với hai trang khác nhau ("index.html" và "other.html") đều kế thừa từ "base.html":

// Content of base.html:
{{define "base"}}<html>
  <head>{{template "head" .}}</head>
  <body>{{template "body" .}}</body>
</html>{{end}}

// Content of index.html:
{{define "head"}}<title>index</title>{{end}}
{{define "body"}}index{{end}}

// Content of other.html:
{{define "head"}}<title>other</title>{{end}}
{{define "body"}}other{{end}}

Và bản đồ bộ mẫu sau:

tmpl := make(map[string]*template.Template)
tmpl["index.html"] = template.Must(template.ParseFiles("index.html", "base.html"))
tmpl["other.html"] = template.Must(template.ParseFiles("other.html", "base.html"))

Bây giờ bạn có thể hiển thị trang "index.html" của mình bằng cách gọi

tmpl["index.html"].Execute("base", data)

và bạn có thể hiển thị trang "other.html" của mình bằng cách gọi

tmpl["other.html"].Execute("base", data)

Với một số thủ thuật (ví dụ: quy ước đặt tên nhất quán cho các tệp mẫu của bạn), bạn thậm chí có thể tạo tmplbản đồ tự động.


3
có thể có dữ liệu mặc định, ví dụ, cho "head" không?
gregghz

18
Tôi sẽ chỉ thêm vào đây điều đó để hiển thị các mẫu thực tế mà tôi phải gọi tmpl["index.html"].ExecuteTemplate(w, "base", data).
hermansc

base.html được phân tích cú pháp và lưu trữ hai lần. Bạn cũng có thể sử dụng hàm Clone () như trong golang.org/pkg/text/template/#example_Template_share
Maarten O.

3
Tôi đang gặp sự cố khi chuyển dữ liệu sang mẫu lồng nhau. Dữ liệu từ {{ .SomeData }}sẽ không được hiển thị trong mẫu bên trong. Các công trình bên ngoài.
0xAffe

nó quan trọng nếu template.ParseFiles("index.html", "base.html")template.ParseFiles("base.html", "index.html")?
shackra

10

lưu ý, khi bạn thực thi mẫu cơ sở của mình, bạn phải chuyển các giá trị xuống các mẫu con, ở đây tôi chỉ cần truyền ".", để mọi thứ được truyền xuống.

mẫu một hiển thị {{.}}

{{define "base"}}
<html>
        <div class="container">
            {{.}}
            {{template "content" .}}
        </div>
    </body>
</html>
{{end}}

mẫu hai hiển thị {{.domains}} được chuyển vào cấp độ gốc.

{{define "content"}}
{{.domains}}
{{end}}

Lưu ý, nếu chúng tôi đã sử dụng {{template "content".}} Thay vì {{template "content".}}, Thì miền .domain sẽ không thể truy cập được từ mẫu nội dung.

DomainsData := make(map[string]interface{})
    DomainsData["domains"] = domains.Domains
    if err := groupsTemplate.ExecuteTemplate(w, "base", DomainsData); err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
    }

5
Chuyển xuống mô hình là một chi tiết tôi đã bị mắc kẹt. ;) Cảm ơn
Patrick

1
tôi quá - mất một chút để tìm ra :)
robert vua

1
Gì! Tôi không thể tin rằng có nhiều ý nghĩa trong dấu chấm nhỏ ở cuối trình giữ chỗ {{template}}! Tại sao điều đó không được đề cập ở bất cứ đâu trong các hướng dẫn, hoặc thậm chí là tài liệu chính thức về cờ vây ?? Tôi rất bối rối ... nhưng cũng rất vui vì đã tìm thấy câu trả lời của bạn! Cảm ơn bạn rất nhiều, bây giờ các mẫu của tôi với một số cấp độ lồng nhau hoạt động rất đẹp!
Gwyneth Llewelyn

Chính xác, điều tương tự mà tôi đã cố gắng tìm ra!
devforfu

5

đã làm việc với các gói mẫu khác, bây giờ tôi chủ yếu làm việc với gói html / mẫu tiêu chuẩn, tôi đoán tôi đã ngây thơ khi không đánh giá cao sự đơn giản mà nó cung cấp và các tính năng bổ sung khác. Tôi sử dụng một cách tiếp cận rất giống với câu trả lời được chấp nhận với những thay đổi sau

bạn không cần bao bọc các bố cục của mình bằng basemẫu bổ sung , một khối mẫu được tạo cho mọi tệp được phân tích cú pháp, vì vậy trong trường hợp này, nó là thừa, tôi cũng muốn sử dụng hành động khối được cung cấp trong phiên bản go mới, điều này cho phép bạn có nội dung khối mặc định trong trường hợp bạn không cung cấp một trong các mẫu con

// base.html
<head>{{block "head" .}} Default Title {{end}}</head>
<body>{{block "body" .}} default body {{end}}</body>

và các mẫu trang của bạn có thể giống với

// Content of index.html:
{{define "head"}}<title>index</title>{{end}}
{{define "body"}}index{{end}}

// Content of other.html:
{{define "head"}}<title>other</title>{{end}}
{{define "body"}}other{{end}}

bây giờ để thực thi các mẫu bạn cần phải gọi nó như vậy

tmpl["index.html"].ExecuteTemplate(os.Stdout, "base.html", data)

4

Sử dụng Pongo , là bộ siêu tập các Mẫu Go hỗ trợ các thẻ {{expand}} và {{block}} để kế thừa mẫu, giống như Django.


4

Tôi đã quay lại câu trả lời này trong nhiều ngày, cuối cùng đã cắn đạn và viết một lớp trừu tượng nhỏ / bộ xử lý trước cho điều này. Về cơ bản thì:

  • Thêm từ khóa 'mở rộng' vào các mẫu.
  • Cho phép ghi đè các lệnh gọi 'xác định' (do đó có thể có các giá trị mặc định cho greggory)
  • Cho phép các cuộc gọi 'mẫu' không được xác định, chúng chỉ đưa ra một chuỗi trống
  • Đặt giá trị mặc định là. trong các cuộc gọi 'mẫu' tới. của cha mẹ

https://github.com/daemonl/go_sweetpl

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.