译者 | 布加迪
审校 | 重楼
HTML让您可以使用扩展的HTML语法而不是JavaScript来实现交互性。HTMX直接在标记中为您提供了HTTP交互,它支持其他许多交互要求,无需借助JavaScript。这个有意思的想法最终可能会影响Web前端的工作方式。不妨看看如何使用HTMX以及什么让它如此引人注目。
HTMX简介
HTMX已经存在了一段时间,但它一直是比较低调的项目。它最近被GitHub Accelerator接受可能会改变这一切。其基本想法是拿来需要模板JavaScript和HTML交互的常见用例,径直使用HTML语法,无需借助JavaScript。许多交互使用HTMX变成了声明式交互。
这听起来大有希望,是不是?每个Web开发人员都知道有许多常见的样板案例。HTMX的开发者Carson Gross表示,他希望“完成HTML作为一种超文本,增强它的表现力,使它成为更高级的现代Web应用程序之外的一种颇有竞争力的选择。”
要快速体验一下,请看这个HTMX演示。大致来说,我们点击一个按钮来编辑用户对象上的字段。数据实际上被PUT(放入)到后端端点。您可以在图1中看到演示,请注意点击Show后底部框中的网络交互。
图1. 表单演示:HTMX
通常,这一切都需要某种JavaScript,无论您使用什么框架。HTMX将交互转变为两个标记块:一个用于显示UI,另一个用于编辑UI,如代码片段1所示。
代码片段1:HTMX中的用户更新
<div hx-target="this" hx-swap="outerHTML">
<div><label>First Name</label>: Joe</div>
<div><label>Last Name</label>: Blow</div>
<div><label>Email</label>: joe@blow.com</div>
<button hx-get="/contact/1/edit" class="btn btn-primary">
Click To Edit
</button>
</div>
<!-- The edit: -->
<form hx-put="/contact/1" hx-target="this" hx-swap="outerHTML">
<div>
<label>First Name</label>
<input type="text" name="firstName" value="Joe">
</div>
<div class="form-group">
<label>Last Name</label>
<input type="text" name="lastName" value="Blow">
</div>
<div class="form-group">
<label>Email Address</label>
<input type="email" name="email" value="joe@blow.com">
</div>
<button class="btn">Submit</button>
<button class="btn" hx-get="/contact/1">Cancel</button>
</form>
如果您查看代码片段1中的标记,就很容易看出具体发生了什么:hx-swap属性在编辑之前为div提供了HTML,而outerHTML告诉框架它如何与其中的动态内容相关联。可编辑版本作为含有x-put属性的表单元素出现,该属性标识PUT HTML方法以及要使用的端点。
问题变成了如何在不借助任何JavaScript的情况下实现这种“交换”和随后的PUT?答案很简单:它为编辑标记使用HTML的服务器端呈现,并将表单编组抽象到框架中。JavaScript仍然在幕后工作。实际上,我们得到了一种粒度更细的HTML语法,它可以只加载页面部分而不是整个页面,并可以提交Ajax请求。
这是实际DRY原理的一个有趣的例子。即使是像React这样的技术,也有一定数量的样板代码将信息从一种形式转换为另一种形式。当然,HTMX没有完全消除这种情况,但它已经将工作转移到服务器上。
服务器端HTMX
现在不妨考虑服务器端。许多服务器端技术都使用了HTMX,因为正如Gross所说,HTMX“与后端无关”。它不在乎您使用什么后端,只要它生成HTML就行。”为了大致了解它是如何工作的,不妨看一个使用Express的TODO示例以及Pug HTML模板引擎。这个示例是经典TODO应用程序的实现。
首先,使用以下命令从Express输出现有的待办事项:
res.render('index', { todos: filteredTodos, filter, itemsLeft: getItemsLeft()
});
该命令使用内存中的待办事项集合,并使用典型格式的Pug模板来呈现它们,只不过它含有驱动HTMX交互的特殊hx-属性。比如说,代码片段2显示了POST新待办事项的表单。
代码片段2. 拥有HTMX属性的表单POST
form(hx-post="/todos", hx-target="#todo-list", hx-swap="afterbegin", _="on htmx:afterOnLoad set #txtTodo.value to ''")
input#txtTodo.new-todo(name="todo",placeholder='What needs to be done?', autofocus='')
您可以在这里(https://htmx.org/docs/#swapping)看到afterbegin属性如何将新内容放在列表中它所属的位置的。on htmx脚本是Hyperscript的一个例子,Hyperscript是一种简化的脚本语言。它经常与HTMX结合使用,但严格来说并不是HTMX的一部分,也不是需要它才能使用HTMX。实际上,这里使用on htmx来处理在创建新待办事项之后设置输入表单的值。
另一个示例是,代码片段3显示了用于待办事项编辑的Pug模板。
代码片段3. 在PUG中编辑服务器端模板
form(hx-post="/todos/update/" + todo.id)
input.edit(type="text", name="name",value=todo.name)
在代码片段3中,标记使用hx-post属性指示将编辑后的待办事项的JSON发送到何处。从这些示例中得出的结论是我在前面提到的:服务器负责提供HTML(用HTML标记装饰),采用适当大小的块,以填充前端用于各种交互所需的屏幕的不同部分。HTMX客户端将根据属性将它们放置在本该所属的位置,还将处理这项任务:发送适当的数据供服务使用。
负责接收数据的端点可以像典型端点一样操作,不同之处在于响应应该是必需的HTMX。比如,在代码片段4中,您可以看到Express服务器如何处理POST以创建新的待办事项。
代码片段4. 处理待办事项创建
app.post('/todos', (req, res) => {
const { todo } = req.body;
const newTodo = {
id: uuid(),
name: todo,
done: false
};
todos.push(newTodo);
let template = pug.compileFile('views/includes/todo-item.pug');
let markup = template({ todo: newTodo});
template = pug.compileFile('views/includes/item-count.pug');
markup += template({ itemsLeft: getItemsLeft()});
res.send(markup);
});
代码片段4是一个典型的POST主体处理程序,它从表单数据中获取值,并用它创建一个新的业务对象(newTodo)。然而,它随后使用这些值来填充Pug模板,并将其发回给客户端,以便用作插入到前端上的Todo列表。
服务器端技术的其他例子包括在Java界结合使用HTMX和Spring Boot与Thymeleaf,在Python界结合使用Spring Boot和Django。
使用HTMX的客户端模板
这种模式的另一种变体得到HTMX的支持,它使用客户端模板。这一层在客户机中运行,接收来自服务器的JSON,并在服务器上进行标记翻译。当我向Gross询问如何使用带有JSON的可充分利用REST的服务时,他指出可以使用客户端模板来实现,但要注意的是REST通常被误解了。
那么一个相反的问题是,我们如何向服务器提交JSON而不是默认的表单编码?再说一次,这有一个相应的扩展,即JSON-ENC。
结论
考虑HTMX会引发一大堆想法同时出现。结果是,这个概念与项目本身一样有益。作为一个成熟的项目,HTMX可能不会像现在这样精确地工作,但它已经证明了具有重大影响力。最引人注目的是这个想法:处理所有这些非常常见的Ajax风格的请求,这通常意味着使用fetch()或类似的东西,仅仅只有HTML属性。这样更简单、更干净,而且所有东西都放在一个地方。标记具体做什么一目了然。
我对服务器端标记生成比较矛盾。开发人员习惯于为此目的处理JSON,引入标记只是为客户端创建添加了一个步骤。我们已经看到了许多服务器端方法,它们似乎总是混淆HTML、JavaScript和CSS这个强大的组合,而这个组合最终将继续笑到最后。也许这一回会有所不同,这里存在明显的钟摆效应。
当然,还有客户端模板选项,它使服务器成为一个熟悉的JSON发射器(emitter)。我试着想象它在一个大型软件项目中会如何工作。它会降低大规模项目的总体复杂性吗?
Gross对复杂性有其自己的看法,他的想法在HTMX的设计中得到了体现。这项技术希望通过将超文本重新作为Web应用程序的状态机制来达到简化的目的。这个示例(表明了这个想法具体是如何实现的。使用JSON作为协议,意味着使客户端更智能、更复杂,并且使架构少一点自我描述。
也许它完全行得通。如果我们通过扩展底层语言HTML以实际处理现代需求(就像Ajax那样)、避免固有的复杂性,有望回到更简单的时代。标记将再次成为中心数据描述符,足以描述UI以及线上的数据。
原文标题:Intro to HTMX: Dynamic HTML without JavaScript,作者:Matthew Tyson