視圖轉換

我們已經主張一段時間了,許多人採用單頁應用程式(SPA)架構來開發 Web 應用程式的主要原因之一是出於美學考量。

正如我們在 超媒體系統 一書中所提到的,當我們討論最初的 Web 1.0 風格的聯絡人管理應用程式時,即使它具有與 SPA 版本相同的功能,該應用程式仍然存在嚴重的美學問題。

從使用者體驗的角度來看:當您在應用程式的頁面之間移動,或者建立、更新或刪除聯絡人時,會有明顯的重新整理。這是因為每次使用者互動(連結點擊或表單提交)都需要完整重新整理頁面,並且在每個動作後都要處理全新的 HTML 文件。

–超媒體系統 - 第五章

這種網頁之間令人不快的「喀嚓」聲,通常伴隨著 未樣式化內容的閃爍,一直困擾著我們。雖然現代瀏覽器在某種程度上改善了這種情況(不幸的是,也讓人更不明顯地知道請求正在進行中),但情況仍然很糟糕,特別是與一個精心製作的 SPA 所能達到的效果相比。

現在,在 Web 早期,這並不是什麼大問題。我們有星星在瀏覽器的工具列上繞著恐龍飛舞、燃燒的文字、基於表格的佈局、跳舞的嬰兒等等,而且我們主要將 Web 與 ftp 用戶端等東西進行比較。

標準很低,而時代美好

唉,自那以後,Web 放下了這種幼稚的東西,現在我們被期望向使用者展示精美、吸引人的介面,包括從一個視圖狀態到另一個視圖狀態的流暢轉換。

再次強調,我們認為這就是為什麼許多團隊默認採用 SPA 方法:舊方法看起來…笨拙。

#CSS 過渡

早期的 Web 工程師意識到,Web 開發人員希望在不同的視圖狀態之間提供流暢的過渡,並提供了各種技術來實現這一目標。主要的一個是 CSS 過渡,它允許您指定從一個狀態到另一個狀態的數學過渡

不幸的是,對於 HTML 來說,CSS 過渡只有在使用 JavaScript 時才可用:您必須動態更改元素才能觸發過渡,而「原生」HTML 無法做到這一點。實際上,這意味著只有使用 JavaScript 建立 SPA 的酷炫孩子才能使用這些工具,這進一步鞏固了 SPA 的美學優勢

您可能知道,htmx 透過稍微複雜的 交換模型,讓 CSS 過渡在純 HTML 中可用,我們在舊內容和新內容中都取得元素,並在它們上「設定」屬性。這是一個巧妙的技巧,可以用來使超媒體驅動的應用程式感覺像做得很好的 SPA 一樣流暢。

但是,現在出現了一個新秀:視圖轉換 API

#視圖轉換 API

視圖轉換 API 比 CSS 過渡更有野心,它試圖提供一個簡單、直覺的 API,用於以普通人可以利用的方式將整個 DOM 從一個狀態轉換到另一個狀態。

此外,這個 API 應該不僅在 JavaScript 中可用,還可以在 HTML 中的普通連結和表單中使用,使得使用 Web 1.0 方法建立更漂亮的使用者介面成為可能。

當這個功能可用時,重新訪問「超媒體系統」中的聯絡人應用程式將會很有趣!

但是,在撰寫本文時,該 API 與 CSS 過渡一樣,僅在 JavaScript 中可用,並且僅在 Chrome 111+ 中剛剛發布。

在 JavaScript 中,API 再簡單不過了


  // this is all it takes to get a smooth transition from one 
  // state to another!
  document.startViewTransition(() => updateTheDOMSomehow(data));

這就是我喜歡的 API。

幸運的是,將此 API 包裝在常規 htmx 交換模型周圍非常簡單,這使我們可以在 htmx 中開始探索視圖轉換,甚至在它通常在 HTML 中可用之前!

而且,從 htmx 1.9.0 開始,您可以通過在 hx-swap 屬性中添加 transition:true 屬性來開始試用該 API。

#一個實用範例

因此,讓我們看一下這個與 htmx 結合使用的新奇玩具的簡單範例。

這樣做將涉及兩個部分

#CSS

我們需要做的第一件事是定義我們想要的視圖轉換動畫。

(有關視圖轉換 API 的完整詳細資訊,請參閱記錄它們的 Chrome 開發人員頁面。)


    <style>
       @keyframes fade-in {
         from { opacity: 0; }
       }
    
       @keyframes fade-out {
         to { opacity: 0; }
       }
    
       @keyframes slide-from-right {
         from { transform: translateX(90px); }
       }
    
       @keyframes slide-to-left {
         to { transform: translateX(-90px); }
       }
    
       /* define animations for the old and new content */
       ::view-transition-old(slide-it) {
         animation: 180ms cubic-bezier(0.4, 0, 1, 1) both fade-out,
         600ms cubic-bezier(0.4, 0, 0.2, 1) both slide-to-left;
       }
       ::view-transition-new(slide-it) {
         animation: 420ms cubic-bezier(0, 0, 0.2, 1) 90ms both fade-in,
         600ms cubic-bezier(0.4, 0, 0.2, 1) both slide-from-right;
       }
    
       /* tie the view transition to a given CSS class */
       .sample-transition {
           view-transition-name: slide-it;
       }
        
    </style>

此 CSS 設置使得具有 .sample-transition 類別的內容在移除時會淡出並滑動到左側,而新內容會淡入並從右側滑入。

#HTML

透過 CSS 定義了我們的視圖轉換後,下一步是將此視圖轉換綁定到 htmx 將會變異的實際元素,並指定 htmx 應利用視圖轉換 API


    <div class="sample-transition">
       <h1>Initial Content</h1>
       <button hx-get="/new-content" 
               hx-swap="innerHTML transition:true" 
               hx-target="closest div">
         Swap It!
       </button>
    </div>

在這裡,我們有一個按鈕,它發出 GET 來獲取一些新內容,並使用響應替換最接近的 div 的內部 HTML。

該 div 具有 sample-transition 類別,因此上面定義的視圖轉換將適用於它。

最後,hx-swap 屬性包含選項 transition:true,它告訴 htmx 在交換時使用內部視圖轉換 JavaScript API。

#演示

將所有這些綁定在一起後,我們就可以開始使用 htmx 的視圖轉換 API 了。這是一個演示,它應該在 Chrome 111+ 中有效(其他瀏覽器也可以正常工作,但不會獲得漂亮的動畫)

初始內容

假設您正在 Chrome 111+ 中查看此頁面,您應該會看到上面的內容優雅地滑出到左側,並被從右側滑入的新內容替換。真棒!

#結論

嘿,這真是太棒了,而且一旦你理解了這個概念,就不會花費太多功夫!這個新 API 顯示出很大的希望。

我們認為,視圖轉換是一種令人興奮的新技術,它可以顯著平衡 超媒體驅動的應用程式 和當今使用更廣泛的 SPA 架構之間的競爭。

透過消除 Web 1.0 應用程式的醜陋「喀嚓」聲,SPA 方法的美學優勢將會降低,我們可以減少圍繞「噱頭」的決策,而更多地關注與各種架構相關的實際 技術權衡

我們期待視圖轉換在原生 HTML 中可用,但在此之前,您今天就可以開始在 htmx 中試用它們了!