更新其他內容

當人們初次使用 htmx 時,經常會出現一個問題:

「我需要更新螢幕上的其他內容。我該如何做?」

有很多方法可以做到這一點,在這個範例中,我們將帶您了解其中一些方法。

我們將使用以下基本 UI 來討論這個概念:一個簡單的聯絡人表格,以及表格下方使用 hx-post 將新聯絡人新增至表格的表單。

<h2>Contacts</h2>
<table class="table">
  <thead>
    <tr>
      <th>Name</th>
      <th>Email</th>
      <th></th>
    </tr>
  </thead>
  <tbody id="contacts-table">
    ...
  </tbody>
</table>
<h2>Add A Contact</h2>
<form hx-post="/contacts">
  <label>
    Name
        <input name="name" type="text">  
  </label>
  <label>
    Email
        <input name="email" type="email">  
  </label>
</form>

這裡的問題是,當您在表單中提交新的聯絡人時,您希望上面的聯絡人表格刷新並包含表單剛剛新增的聯絡人。

我們有哪些解決方案?

#解決方案 1:擴大目標

這裡最簡單的解決方案是「擴大表單的目標」,使其包含表格表單。例如,您可以將整個內容包裝在 div 中,然後在表單中以該 div 為目標

<div id="table-and-form">
    <h2>Contacts</h2>
    <table class="table">
      <thead>
        <tr>
          <th>Name</th>
          <th>Email</th>
          <th></th>
        </tr>
      </thead>
      <tbody id="contacts-table">
        ...
      </tbody>
    </table>
    <h2>Add A Contact</h2>
    <form hx-post="/contacts" hx-target="#table-and-form">
      <label>
        Name
            <input name="name" type="text">  
      </label>
      <label>
        Email
            <input name="email" type="email">  
      </label>
    </form>
</div>

請注意,我們正在使用 hx-target 屬性來定位封閉的 div。您需要在對 /contactsPOST 回應中同時呈現表格和表單。

這是一個簡單可靠的方法,儘管它可能感覺不是特別優雅。

#解決方案 2:帶外回應

這個問題更複雜的方法是使用帶外交換將更新的內容交換到 DOM 中。

使用這種方法,HTML 不需要與原始設定有任何變更

<h2>Contacts</h2>
<table class="table">
  <thead>
    <tr>
      <th>Name</th>
      <th>Email</th>
      <th></th>
    </tr>
  </thead>
  <tbody id="contacts-table">
    ...
  </tbody>
</table>
<h2>Add A Contact</h2>
<form hx-post="/contacts">
  <label>
    Name
        <input name="name" type="text">  
  </label>
  <label>
    Email
        <input name="email" type="email">  
  </label>
</form>

在您對 /contactsPOST 回應中,您需要包含一些額外內容,而不是修改前端的內容

<tbody hx-swap-oob="beforeend:#contacts-table">
  <tr>
    <td>Joe Smith</td>
    <td>joe@smith.com</td>
  </tr>
</tbody>

<label>
  Name
      <input name="name" type="text">
</label>
<label>
  Email
      <input name="email" type="email">
</label>

此內容使用 hx-swap-oob 屬性將自身附加到 #contacts-table,在成功新增聯絡人後更新表格。

#解決方案 3:觸發事件

更複雜的方法是在成功建立聯絡人時觸發一個客戶端事件,然後在表格上偵聽該事件,導致表格刷新。

<h2>Contacts</h2>
<table class="table">
  <thead>
    <tr>
      <th>Name</th>
      <th>Email</th>
      <th></th>
    </tr>
  </thead>
  <tbody id="contacts-table" hx-get="/contacts/table" hx-trigger="newContact from:body">
    ...
  </tbody>
</table>
<h2>Add A Contact</h2>
<form hx-post="/contacts">
  <label>
    Name
        <input name="name" type="text">  
  </label>
  <label>
    Email
        <input name="email" type="email">  
  </label>
</form>

我們新增了一個新的端點 /contacts/table,它會重新呈現聯絡人表格。此請求的觸發器是自訂事件 newContact。我們在 body 上偵聽此事件,因為當它由表單的回應觸發時,由於事件冒泡,它最終會觸及 body。

當在對 /contacts 的 POST 期間成功建立聯絡人時,回應會包含一個 HX-Trigger 回應標頭,如下所示

HX-Trigger:newContact

這將觸發表格向 /contacts/table 發出 GET,這將呈現新新增的聯絡人行
(以及表格的其餘部分。)

非常乾淨、事件驅動的程式設計!

#解決方案 4:使用路徑依賴項擴展

最後一種方法是使用 RESTful 路徑依賴項來刷新表格。htmx 的前身 Intercooler.js 將基於路徑的依賴項整合到程式庫中。

htmx 放棄了這個作為核心功能,但支援一個擴展,path deps,它為您提供類似的功能。

更新我們的範例以使用擴展將涉及載入擴展 javascript,然後像這樣註解我們的 HTML

<h2>Contacts</h2>
<table class="table">
  <thead>
    <tr>
      <th>Name</th>
      <th>Email</th>
      <th></th>
    </tr>
  </thead>
  <tbody id="contacts-table" hx-get="/contacts/table" hx-ext="path-deps"  hx-trigger="path-deps" path-deps="/contacts">
    ...
  </tbody>
</table>
<h2>Add A Contact</h2>
<form hx-post="/contacts">
  <label>
    Name
        <input name="name" type="text">  
  </label>
  <label>
    Email
        <input name="email" type="email">  
  </label>
</form>

現在,當表單發佈到 /contacts URL 時,path-deps 擴展將檢測到這一點,並在聯絡人表格上觸發一個 path-deps 事件,從而觸發請求。

這裡的優點是您不需要對回應標頭執行任何花俏的操作。缺點是在每次 POST 時都會發出請求,即使未成功建立聯絡人也是如此。

#我應該使用哪個?

一般來說,我建議第一種方法,擴大您的目標,尤其是當需要更新的元素在 DOM 中彼此相當接近時。它既簡單又可靠。

在那之後,我認為自訂事件和 OOB 交換方法之間勢均力敵。我會傾向於自訂事件方法,因為我喜歡事件導向的系統,但這是一種個人偏好。您選擇哪一個應由您自己的軟體工程品味以及哪一個更符合您選擇的伺服器端技術來決定。

最後,路徑依賴項方法很有趣,如果它與您的心智模型和整體系統架構非常吻合,那麼它可以成為避免明確刷新的有趣方式。但是,我會最後考慮它,除非這個概念真的吸引您。