天天看點

go post 參數_Go 語言 Web 架構 Echo 系列:定制篇4—自定義 Renderer,增強或替換模闆引擎...

Render,顧名思義,要進行頁面渲染。Go 語言不但自帶有強大的 http 庫,還自帶了 HTML 模闆引擎。Echo 架構對模闆引擎進行了一些額外處理,并提供了給使用者自定義頁面渲染的接口。本文就相關問題進行探讨。

模闆渲染

Echo 架構的 Context 接口提供了下面的方法進行頁面渲染:

// echo 包中 Context 接口的方法
           

其中,code 是 HTTP Status,name 是定義的模闆名,data 是模闆可能需要的資料。執行這個方法後,通過資料渲染模闆,并發送帶有 HTTP 狀态的 text/html 響應。可以通過 Echo.Renderer 來注冊模闆,進而允許我們使用任何模闆引擎。

Renderer 接口定義如下:

// Renderer is the interface that wraps the Render function.
           

這裡可能會有點迷糊,怎麼有兩個 Render 方法,而且它們的簽名還不一樣。這裡的邏輯是這樣的:

  • echo.Echo 類型有一個 Renderer 接口類型的字段,用來注冊模闆引擎;
  • echo.Context 接口類型有一個 Render 方法,在 Handle 中我們通過調用 Context 的 Render 方法進行模闆渲染;
  • 在 Context 的 Render 方法内部(當然是 echo 中 Context 接口的預設實作),會調用 echo.Echo 的字段 Renderer 的 Render 方法,進行具體的模闆渲染;

這裡是具體的渲染源碼:

可見,如果調用了 Context#Render 進行模闆渲染,但并沒有注冊模闆引擎則會報錯(ErrRendererNotRegistered)。

內建标準庫模闆引擎

1、我們先定義一個類型:Template,然後實作 Echo.Renderer 接口,即提供 Render 方法。

type Template 
           

2、接着預編譯一個模闆。定義一個模闆檔案:template/index.html,内容如下:

然後預編譯得到 Template 的執行個體:

3、注冊模闆引擎:

4、在 Handler 中渲染模闆:

"/", 
           

注意這裡的 index 是模闆檔案中

define "index"

,而不是檔案名。

編譯後運作,浏覽器正常顯示:Hello,studygolang!

go post 參數_Go 語言 Web 架構 Echo 系列:定制篇4—自定義 Renderer,增強或替換模闆引擎...

通用化定制

一般的,頁面會有一些通用的部分,比如頭部、尾部等。是以業界通常的做法是有一個 layout,而且還可能不止一個 layout,因為普通使用者看到的和背景看到的頭部、尾部一般會不一樣。那這樣的通用化定制需求該如何內建到 Echo 的 Render 中呢?

先考慮隻有一種 layout 的情況。定義一個類型 layoutTemplate,實作 Echo.Renderer 接口:

type layoutTemplate 
           

然後注冊該 Renderer,并在 Handler 中渲染,注意 ctx.Render 的第二個參數,跟上面說的不一樣,我們傳遞的是子模闆的檔案名:index.html。

這裡用到了兩個模闆檔案:layout.html 和  index.html,來源 Hugo 的 soho 這個模闆。

html>
           

這是 layout.html 的内容,核心在于

{{template "content" .}}

,表示具體内容模闆需要定義 content,是以看看 index.html 檔案:

運作後打開浏覽器通路 http://localhost:2020 :

go post 參數_Go 語言 Web 架構 Echo 系列:定制篇4—自定義 Renderer,增強或替換模闆引擎...

接下來看看如何處理多個 layout 的情況。

因為 Render 的簽名是固定的,不同的 layout 通過什麼方式告知 Render 呢?觀察 Render 方法的參數:

string, data 
           

可以在 data 和 ctx 上下功夫:

  1. 将 data 指定為 map[string]interface{},layout 通過 data 傳遞;
  2. 通過 ctx 的 Set 方法設定 layout,方法内通過 ctx.Get 擷取 layout;

先看第 1 種方式:

// NoNavRender 沒有導航的 layout html 輸出
           

在 render 包中增加了一個 NoVaRender 函數,該函數要求 data 必須是 map[string]interface{},這樣就可以做到将 layout 傳遞給 Render 方法,不過因為 Render 方法的 data 參數是 interface{} 類型,是以得做類型斷言。

"layout.html"
           

看看第 2 種方式如何實作:

// NoNavRender 沒有導航的 layout html 輸出
           

在 Render 中擷取 layout 的值:

"layout.html"
           

兩種方式個人覺得第 2 種更優雅。不過需要注意的是,兩種方式要注意 layout 不能沖突,也就是不能他用。

另外,我個人建議,data 參數永遠要麼傳遞 nil,要麼傳遞 map[string]interface{} 。個人感覺 Echo 的 Render 方法 data 參數的類型不應該用 interface{} 而是用 map[string]interface{},這樣可以更友善地往 data 中加入更多全局的資料。在簡書項目中,我們會通過其他方式彌補這個問題。

小結

通過本節,你應該掌握了 Render 的使用、內建和大項目 layout 的處理。

額外提一句,因為 Context.Render 方法最終是調用的 Context.HTML 方法進行渲染,是以我們也完全可以抛棄 Render 方法,而是使用自己的 Render。目前簡書的代碼(後續會改掉)和 studygolang 的源碼采用的就是完全抛棄 Context.Render 的方式,主要考慮還是有一些 Render 不能很好滿足的地方,比如上面說的多 layout、data 類型等,不過也是可以解決的。是以還是建議采用 Echo 架構的 Render。

本節完整代碼點這裡: https://github.com/polaris1119/go-echo-example/tree/0cd46e8b1f38317439e95d55e3fe29a173a2e3c1。

覺得不錯,歡迎關注:

go post 參數_Go 語言 Web 架構 Echo 系列:定制篇4—自定義 Renderer,增強或替換模闆引擎...

點個贊、在看和轉發是最大的支援