视图过渡

我们已经断言,现在,许多人采用 SPA 架构用于 Web 应用程序的主要原因是由于审美方面的考虑。

正如我们在我们的书中提到的那样 超媒体系统,在讨论我们从头开始的 Web 1.0 风格的联系人管理应用程序时,即使与 SPA 版本具有功能奇偶校验,该应用程序也存在严重的 *审美* 问题。

从用户体验的角度来看:当您在应用程序的页面之间移动,或创建、更新或删除联系人时,会出现明显的刷新。这是因为每次用户交互(链接点击或表单提交)都需要完全刷新页面,并在每次操作后处理一个全新的 HTML 文档。

–超媒体系统 - 第 5 章

这种网页之间的令人不快的“ka-chunk”,通常带有 未格式化内容闪烁 一直伴随着我们,尽管现代浏览器在一定程度上改善了这种情况(虽然不幸的是也让请求正在进行变得不太明显),但这种情况仍然很糟糕,尤其是在与精心制作的 SPA 所能达成的效果相比时。

现在,在网络早期,这不是什么大问题。我们在 *浏览器的工具栏* 中有围绕恐龙飞行的星星、火焰文字、基于表格的布局、跳舞的婴儿等等,而且我们主要是在将网络与诸如 ftp 客户端之类的工具进行比较。

门槛很 *低*,时代很好。

唉,网络已经放弃了这些幼稚的东西,现在我们被期望为我们的用户提供抛光、有吸引力的界面,*包括* 从一个视图状态到另一个视图状态的平滑过渡。

再说一遍,我们认为这就是许多团队默认使用 SPA 方法的原因:旧方法看起来太…笨拙了。

#CSS 过渡

早期的网络工程师意识到,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 应用程序中难看的“ka-chunk”,SPA 方法的审美优势将减弱,我们可以减少围绕“sizzle”的决策,更多地关注与各种架构相关的实际 技术权衡

我们期待着视图过渡在普通 HTML 中可用,但在此之前,您今天就可以开始在 htmx 中使用它们!