Django、HTML 和 Alpine.JS:天作之合
如果你想看看 HTMX 和 Alpine.JS 是如何协同工作的,请点击这里查看我使用这两者搭建的一个基本项目。
如果您需要帮助将您的数字创意变为现实,请联系摩恩数字服务部门。
目录
- 介绍
- HTMX是什么?
- Alpine.JS是什么?
- 为什么要同时使用 HTMX 和 Alpine.JS?
- HTMX 和 Alpine.JS 的协同工作效果如何?
- 关于在 Django 中使用 HTML 的注意事项
- 结论
介绍
我一直在尝试找到一种方法,既能保留 Django 等传统服务器端框架的特性,又能提供类似 React、Vue、Angular 和 Svelte 等前端 JavaScript 框架(以及其他框架)所提供的现代 Web 体验。具体来说,我希望能够在更新页面元素的同时,始终保持 Web 应用程序的状态不变。此外,我还希望能够利用这些框架的优势,轻松地为 Web 应用程序添加功能,而无需编写大量的样板代码。
Django(以及其他服务器端框架)可以与这些前端框架很好地配合使用,但这需要使用 REST 框架,这限制了 Django 的实用性,特别是其渲染 HTML 模板的能力,以及其会话管理功能,这些功能使得管理用户身份验证和会话变得容易。
虽然 Django 对我来说非常好用,但它给我的感觉仍然像是为另一个时代设计的。默认情况下,它会生成纯 HTML 模板,其中包含链接,点击链接后,屏幕会清空,并填充新获取的模板。虽然没有规定必须这样使用,但这是我理解 Django 工作流程的方式。当然JSONResponse,还有其他方法,但这需要对数据进行处理、操作 DOM 元素等等。
如果有一种方法可以保留给定页面的大部分内容,但可以轻松地将页面的某些部分替换为新数据,那会怎么样?
这就需要用到HTMX了。
HTMX是什么?
HTMX的创建者将其描述为“功能强大的 HTML 工具”。
它的功能与 Ajax 或fetch()调用非常相似,但也有一些显著的区别:
- HTML 允许从任何元素调用 GET/POST/PUT/DELETE 等方法,而不仅仅是 <div>
<form>和 <span><a>。 - HTML 允许您指定一个 DOM 目标,并用新获取的数据替换它。
- HTMX(默认情况下)期望接收 HTML 内容,而不是获取 JSON 数据。
基于这些原则,HTML 可以将部分控制权交还给服务器端框架(例如 Django),因为你不再需要处理传入的数据。你只需创建一个作为伪端点的视图,将数据渲染到模板中,然后将该模板插入到目标 DOM 元素中即可。
以下是HTMX的使用示例:
<button hx-post="/clicked"
hx-swap="outerHTML"
hx-target="#your-target-element">
Click Me
</button>
<div id="#your-target-element">
This content will be replaced.
</div>
hx-post允许您指定使用的请求方法(GET/POST/PUT/DELETE 等)。hx-target指定服务器返回响应时要替换其内容的元素的 CSS 选择器。hx-swap描述传入数据相对于目标元素的放置方式。新数据可以追加/前置到旧数据,也可以完全替换旧数据,等等。
如您所见,添加一些 HTML 属性可以让您的 HTML 代码更有能力生成类似应用程序的体验。
虽然我的演示项目只在基本的数据获取和交换之前使用了 HTML,但 HTML 是一个功能相当强大的库,可以执行很多任务。您可以在 HTML 的示例页面上看到一些 HTML 强大功能的示例。
Alpine.JS是什么?
简而言之,Alpine.js 是 Vue.js 的轻量级版本。它是一个小型库,可以轻松地为 Web 应用添加响应式设计(即状态更改会立即反映在应用中),并提供一些其他提升用户体验的功能。与 HTML 类似,它是一个 JavaScript 库,通过添加内联 HTML 属性来使用。
以下是一个基本的阿尔卑斯式组件示例:
<div x-data="myComponent()">
<div>
The value is <span x-text="myValue"></span>.
</div>
</div>
<script>
function myComponent() {
return {
myValue: 5
}
}
// The component will be rendered as "The value is 5."
</script>
Alpine.js 可用于过渡效果、条件渲染和事件处理,以及遍历数组……它简直就是 Vue 的小兄弟。甚至语法也几乎完全相同:比较一下创建事件监听器的 HTML 语法:v-on:click(Vue)与x-on:click(Alpine)。Alpine 甚至沿用了相同的简写语法(它们都使用 ` @click<click>` 作为创建点击事件监听器的简写)。
那么,为什么要使用 Alpine 而不是 Vue 呢?Vue 使用虚拟 DOM(简称 VDOM)来更高效地管理应用程序状态,然后再更新实际的 DOM。任何直接操作 DOM 的组件(例如 jQuery)都可能导致 Vue 出现问题,因为 VUE 使用的是 VDOM,而当某些组件在 VDOM 不知情的情况下直接操作 DOM 时,就会出现问题。与 Vue 不同,Alpine 不使用 VDOM,而是直接操作 DOM。这意味着通过 HTML 获取的任何 HTML 模板都不会像在使用 VDOM 的框架中那样干扰 Alpine 的功能。
与其他框架一样,Alpine 也提供了一个浏览器扩展程序,用于检测、检查、编辑和调试 Alpine.js 的数据和组件。该扩展程序名为Alpine.js devtools,适用于Chrome和Firefox浏览器。
Alpine 还具有一个名为Spruce 的第三方状态管理层,它为组件之间相互通信提供了一种方式,并充当应用程序数据的单一数据源。它类似于 React Redux 或 Vuex。
更新:Alpine v3 现在内置了状态管理系统。
为什么要同时使用 HTMX 和 Alpine.JS?
就我的使用场景而言,HTML 负责切换页面元素,而 Alpine 则用于切换导航栏和模态框、设置按键事件监听器来关闭模态框,以及为两者添加过渡效果等操作。我发现,在为 Web 应用添加类似单页应用 (SPA) 的体验时,HTML 承担了大部分工作,而 Alpine 则有助于优化 UI 流程,并减少我为完成常见任务所需的 JavaScript 代码量。Alpine 还允许你在 window 对象上设置事件监听器,这非常方便,例如,无论哪个元素被选中,都可以使用 Esc 键关闭模态框(模态框也是使用 Alpine 的x-if属性进行条件渲染的,因此监听器仅在模态框处于活动状态时才会启用)。
HTMX 和 Alpine.JS 的协同工作效果如何?
总的来说,我发现这两者配合得非常好。我能够轻松地使用HTMX和Alpine。
我在创建演示项目时确实遇到了一些这两个库的问题,但在撰写本文时未能重现这些问题。(如果您在使用这两个库时遇到任何问题,请在评论区分享您的经验。)
对于客户端表单验证,我发现 HTML会触发一些与表单验证相关的事件,但我发现使用 JavaScript + Alpine 处理提交操作,然后在完成验证后使用 HTML 的 JavaScript API 调用它,会更加简单。例如:
<form x-data="myForm()"
@submit.prevent="submitForm">
<input type="text" id="my-text" name="mytext">
<input type="submit">
</form>
<div id="form-result"></div>
<script>
function myForm() {
return {
submitForm() {
// get the value of #my-text
let myText = document.querySelector(#my-text).value;
// if myText is empty, do not continue
if (!myText) {
console.log('Something went wrong.');
return false;
} else {
// submit the form using HTMX
htmx.ajax(
'POST',
'https://your.server/form-url/', {
target: '#form-result',
values: { text: myText }
});
}
}
}
}
</script>
关于在 Django 中使用 HTML 的注意事项
HTML 和 Django 是绝佳搭档。你可以使用 Django 的函数通过模板渲染响应render,或者返回一个HttpResponse与 JSX 极为相似的字符串:
from django.http import HttpResponse
def my_view(request, your_name):
return HttpResponse(f"""
<div>
Hello, {your_name}!
</div>
""")
您可以返回脚本:
from django.http import HttpResponse
def my_view(request, your_name):
return HttpResponse(f"""
<script>
// this will execute immediately
console.log("Hello, {your_name}!");
</script>
""")
您还可以向 HTTP 响应添加状态码:
def my_view(request, your_name):
if not your_name.isalpha():
response = HttpResponse("That's not a real name!")
response.status_code = 400 # bad request
return response
return HttpResponse(f"""
<div>
Hello, {your_name}!
</div>
""") # HttpResponse returns status code 200 by default
请注意,如果返回 302 响应,HTML 不会更改内容,因此如果您不想更改内容,可以返回 302:
def my_view(request, your_name):
if not your_name.isalpha():
response = HttpResponse()
response.status_code = 302
return response
return HttpResponse(f"""
<div>
Hello, {your_name}!
</div>
""")
在 HTML 请求中添加 CSRF 令牌标头
由于 Django 表单(以及任何其他接受非 GET 方法的视图)需要 CSRF 令牌,因此必须将以下脚本添加到页面主体的底部,以便 HTML 可以自动将传入的 CSRF 令牌添加到其标头中,从而使 Django 能够接受来自 HTML 的任何非 GET 请求(感谢Matt Layman 的贡献):
<script>
document.body.addEventListener(
'htmx:configRequest', (event) => {
event.detail.headers['X-CSRFToken'] = '{{ csrf_token }}';
})
</script>
结论
HTML 和 Alpine.js 配合使用效果极佳,能够打造沉浸式、流畅的网页体验。借助 HTML,您可以轻松更新页面片段,而无需重新加载整个页面。Alpine.js 则提供了响应式设计以及其他提升前端体验的功能。此外,您还可以保留自己的 DOM,不受其他前端框架的限制。
使用这两个库还可以保留您的服务器端框架及其所有功能,特别是模板和会话身份验证。
我将继续使用 HTMX 和 Alpine.JS,并希望它们将来也能像现在这样为我提供良好的服务。
来看看我的演示项目,它展示了 HTMX 和 Alpine.JS 的协同工作。
文章来源:https://dev.to/nicholas_moen/what-i-learned-while-using-django-with-htmx-and-alpine-js-24jg