htmx:後端主導的前端框架是啥樣的?
大家好,我卡頌。
前端領域這幾年湧現了很多新興的前端框架,比如Qwik
、Svelte
、Astro
等。
這些框架多以 「前端工程師」 作爲受衆。
那麼,以 「後端工程師」 作爲受衆的前端框架是啥樣的,他與前者有什麼區別呢?
介紹 htmx
htmx
是一款在Django
技術棧最近比較熱門的前端框架。
他的理念是 —— 「讓網頁迴歸 HTML 的本質,不再受 JS 束縛」。是不是很有web1.0
的風格?
他是怎麼做到的呢?答案是:通過大量預製的自定義HTML
屬性。
當你在頁面中引入htmx.org.js
後,可以在HTML
中書寫以hx-
開頭的自定義屬性。比如下面的代碼:
<button
hx-post="/data"
hx-trigger="click"
>
點我請求data
</button>
點擊按鈕(hx-trigger
指定的click
事件)後,會向data
接口(hx-post
指定)發起post
請求。
那請求返回的數據如何顯示呢?我們再增加 2 個自定義屬性:
<button
hx-post="/data"
hx-trigger="click"
hx-target="#parent-div"
hx-swap="outerHTML"
>
點我請求data
</button>
hx-target
指代 「返回的 HTML 結構」 會被注入到哪裏。這裏會被注入到 「id 爲 parent-div 的 DOM」 中。
hx-swap
指代 「返回的 HTML 結構會以什麼形式注入」。這裏會直接替換 「id 爲 parent-div 的 DOM」。
如果hx-swap="innerHTML"
,則代表會以 「id 爲 parent-div 的 DOM」 的innerHTML
形式注入。
如果要表達複雜的邏輯,需要結合很多自定義屬性與屬性值,比如下面的代碼:
<input
type="text"
hx-get="/trigger_delay"
hx-trigger="keyup changed delay:500ms"
hx-target="#search-results"
placeholder="Search..."
>
當input
觸發keyup
事件且值改變後,延遲 500ms,向trigger_delay
接口發起請求,返回的HTML
結構被注入到 「id 爲 search-results 的 DOM」 中。
與其說htmx
是一款前端框架,更貼切的說,他應該是一款 「HTML 自定義屬性工具庫」。
他將很多常見JS
交互邏輯收斂到自定義HTML
屬性中,藉此減少JS
代碼量。
現代前端框架通常是 「狀態驅動 UI」,而htmx
的理念是 「過程驅動 UI」 (類似jQuery
時代編寫頁面的方式)。
如果希望引入狀態,需要以插件的形式引入alpine-morph
。
相比於:
-
React:基於
JSX
-
Vue:基於模版語法
alpine
是一款基於HTML
的前端框架。
這意味着使用alpine
需要直接在HTML
中以自定義屬性的形式書寫狀態(與Vue v1
類似)。所以,他能很好的融入htmx
的體系中。
比如下面這段代碼是段結合htmx
與alpine
的HTML
,其中以hx-
開頭的是htmx
屬性,以x-
開頭的是alphine
屬性:
<div hx-target="this" hx-ext="alpine-morph" hx-swap="morph">
<div x-data="{ count: 0, replaced: false,
message: 'Change me, then press the button!' }">
<input type="text" x-model="message">
<div x-text="count"></div>
<button x-bind:style="replaced && {'backgroundColor': '#fecaca'}"
x-on:click="replaced = true; count++"
hx-get="/swap">
Morph
</button>
</div>
</div>
這段代碼包含了交互邏輯與前端狀態,最重要的是:他是合法的HTML
(而不是JSX
或模版語法這樣的DSL
),這意味着他能輕鬆的在前後端之間傳遞,並在前端展示。
交互邏輯守恆
本質來說,網頁的最終消費品是HTML
與CSS
。開發者編寫交互邏輯改變HTML
與CSS
。
前端工程師習慣在網頁中通過JS
編寫交互邏輯。
後端工程師習慣在後端編寫交互邏輯。比如在htmx
中,請求返回的是HTML
結構,這部分 「生成 HTML 的邏輯」 是在後端controller
中實現的(而不是在前端通過JS
生成)。
除此之外,還有一部分交互邏輯是在後端 「HTML 模版」 中產生的。下圖是Django
中結合htmx
的後端模版代碼示例:
不管交互邏輯在前端還是後端實現,也不管用哪種語言實現,他是一定需要實現的,也就是說 「交互邏輯守恆」。
但是,交互邏輯在前端還是後端實現,對頁面帶來的影響是不同的。
對頁面性能的影響
交互邏輯在前端實現的越多,意味着 「越多的 JS 代碼」,如果這部分代碼是首屏渲染所需的,那意味着更差的 FCP[1] 指標。
如果這部分代碼是後續交互所需的,那意味着更差的 TTI[2] 指標。
爲了減少前端JS
資源對性能的影響,前端框架都在逐步向後迭代,比如Next.js
之於React
,Nuxt.js
之於Vue
。
新興框架中的Astro
、Qwik
等也是類似思路。
而本文聊的htmx
作爲後端主導的前端框架,本身的立足點就是後端的view
層,所以天生就是頁面性能友好的。
總結
根據 「交互邏輯守恆」,交互邏輯一定需要實現,不是在前端就是在後端。
傳統來說,前端框架將交互放在前端,這會造成JS
資源變大,影響性能。
單純從功能來講,htmx
僅僅是個 「HTML 自定義屬性工具庫」,他將一部分交互收斂到自定義屬性中,減少前端交互邏輯。
剩下的交互邏輯放在後端的view
(作爲頁面模版),或controller
(將HTML
作爲接口返回值),以此減少前端JS
資源的體積。
對於頁面交互複雜度不高,且是後端主導的項目(不想寫JS
邏輯),相信htmx
會是不錯的選擇。
參考資料
[1] FCP: https://web.dev/fcp/
[2] TTI: https://web.dev/tti/
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/kg-ZoEvAxeR0I2P4U1_CkA