Dev Talks

再見了 JavaScript ! 如何用 Hotwire Turbo 快速實現 Partial Load 滿足前端需求

Dante Cheng, 網站工程師 Sep 2, 2022

前言

隨著版本的更新,Hotwire 成為 Rails 7 的預設前端框架,作為不想寫 JavaScript 的 Rails 工程師想當然必須了解一下其基本運作原理以及使用方式。


Hotwire 前端大禮包有什麼?

  • Turbo
  • Stimulus
  • Strada

Turbo

針對獨立區塊的 DOM 元素的替換

Stimulus

針對特殊事件,譬如滑鼠、按鍵等等 DOM 元素的操作

Strada

讓 IOS/Android 與 HTML 互動開發

三大功能,各自解決了前端的問題,但篇幅有限,這邊會先專注 Turbo 跟大家介紹 :D


JavaScript 真的再見了?

並沒有!端看你的前端需求你仍然可能需要使用 Stimulus 寫一點 JavaScript,或是與其他的前端框架並用,但是在符合條件的需求下,是有機會不需要一行 JavaScript 就能完成你的需求。


Hotwire Turbo 幫我做了什麼

首先,運用 HTML Fetch 處理了 AJAX 來取得替換的 Data。

再運用封裝的 JavaScript,讓你只需要透過其自定義的 HTML Tag 就可以替換 DOM 來完成 Partial Load。

而封裝的 JavaScript 中幫你定義好了以下七個動作供你對想替換的 DOM 可做的操作:

  • Update
  • Replace
  • Before
  • After
  • Remove
  • Append
  • Prepend

自己的 Tag 自己做

前面有提到自定義的 HTML Tag,其中運用的是 HTML customElements 物件,以下以 Turbo Stream 為例:

<script>
  const fooActions = {
    // 定義 action replace 替換 innerHTML
    replace(e) {
      const target = document.getElementById(e.target)
      target.outerHTML = e.template.innerHTML
    }
  }

  class FooStream extends HTMLElement {
    constructor() {
      super()

      fooActions[this.action](this) // 執行該 Action
      this.remove() // Stream 替換後會被移除
    }

    get action() {
      return this.getAttribute('action') // 取得 action attribute
    }

    get target() {
      return this.getAttribute('target') // 取得 target attribute 也就是需要對應的 id
    }

    get template() {
      return this.firstElementChild // 取得自訂 Tag 所包裹的內容
    }
  }
  
  customElements.define('foo-stream', FooStream);
</script>


<foo-stream action="replace" target="demo">
  <template>
    <div> Hello Turbo </div>
  </template>
</foo-stream>

<div id="demo"> Hello 5xRuby </div>

上面的這個案例會藉由 demo 這個 ID 對應將有 Hello 5xRuby 文字的 div tag 替換成 Hello Turbo 文字的 div tag,
而這中間因為 Hotwire 已經幫你做好了,你只需要使用 HTML Tag 與 ID 就可以達到對 DOM 替換的功能。


通通包起來就對了!

// edit.html.erb
// 每一個 article 都由 turbo_frame_tag 包住, dom_id 為 tag 的 id

<%= turbo_frame_tag dom_id(@article) do %>
  <%= form_with model: @article do |f| %>
    <%= f.label :title %>
    <%= f.text_field :title %>
    <%= f.label :content %>
    <%= f.text_area :content %>
    <%= f.submit %>
  <% end %>
<% end %>
// index.html.erb
// 當點擊 Edit link 會去找對應的 dom_id 與上面的 form 替換

<%= turbo_frame_tag dom_id(@article) do %>
  <div>Title</div>
  <div><%= article.title %></div>
  <div>Content</div>
  <div><%= article.content %></div>
  <%= link_to 'Edit', edit_article_path(article) %>
  <%= link_to 'Delete', article_path(article), data: { turbo_method: :delete } %>
<% end %>

以編輯文章為例,最後你可以快速做出可針對每個文章獨立的替換出 Edit form 的效果:


選擇比努力更重要

2021年與家昱家合作開發掛號系統,在追求使用者體驗的同時亦要與時間賽跑,五倍開發團隊使用 Hotwire 解決了複雜的 UI/UX 操作,同時兼顧了產品要求、團隊協作以及開發時程,成功在兩個月內讓初版的產品上線。

另外值得一提的是,與時間賽跑的同時也要學習如何應用在專案上,考慮到團隊內所有工程師的技能並不完全重疊,技術的選項則多了學習曲線的變因,所以在同樣的時間與力氣之下,Hotwire 成為了當時團隊中最佳的選擇。


總結

Hotwire 有著較低的學習曲線、HTML Tag 非常容易上手以及不綁定 Rails 可與其他框架一起使用等等優點。

但人世間沒有工具是萬能的,總有些情境並不適用這項工具,所以我們需要做的事情是理解它可以帶給我們什麼樣的便利性,從而選擇出一個適合需求的工具,提升工作效率,才是專案開發的最佳解答。


想要閱讀更多來自五倍紅寶石軟體開發的技術分享?歡迎訂閱我們的月報,每月將自動幫你送上最新文章。


分享