- 前端
【免费下载链接】htmx
htmx - high power tools for HTML
htmx 的preload扩展允许你在用户真正点击之前,就把 HTML 片段提前加载进浏览器缓存,让后续页面看起来"几乎瞬时"呈现。本文以 www/content/extensions/preload.md 为骨架,结合 htmx 核心源码(src/htmx.js)与扩展实现(dist/ext/preload.js),系统讲解安装方式、四种触发模式(mousedown/mouseover/ 自定义事件 /always)、表单与图片的预加载能力、触摸设备适配以及缓存失效的边界条件,帮助你按需配置,在感知性能与服务器负载之间取得平衡。
一、什么是 preload 扩展
在传统的 Web 应用中,用户点击一个链接后,浏览器才发起请求、等待服务器响应、渲染页面。这个往返过程通常要消耗数百毫秒甚至更久。htmx 的preload扩展把"请求"这一步提前:它在你指定的时机(例如鼠标按下、悬停、甚至页面刚解析完)就把目标资源请求回来,存入浏览器缓存。等到用户真正点击时,资源已经就绪,页面呈现近乎瞬时。
从实现上看,扩展通过htmx.defineExtension("preload", {...})注册,并在htmx:afterProcessNode事件中完成对所有带preload属性的节点及其后代链接的初始化,详见 dist/ext/preload.js。
重要提醒:预加载是一把双刃剑。合理预加载可以显著提升感知性能,但预加载过多资源会消耗访客带宽、对服务器发起大量可能根本用不到的请求,从而拖累服务器性能。务必谨慎使用。
二、安装方式
安装preload扩展有多种途径,但无论哪种方式,都必须先引入 htmx 核心库,再引入扩展,并且在页面中使用hx-ext="preload"启用它(启用方法见下一节)。
方式一:通过 CDN 引入(最快)
<head> <script src="https://cdn.jsdelivr.net/npm/htmx.org@2.0.11/dist/htmx.min.js" integrity="sha384-2OatzQy1H+Zd/IIrjr1TcuDGqLXeHhbooAyJY1KdQMKnr4LZ22k31GBLdYKHmVjg" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/htmx-ext-preload@2.1.2" integrity="sha384-PRIcY6hH1Y5784C76/Y8SqLyTanY9rnI3B8F3+hKZFNED55hsEqMJyqWhp95lgfk" crossorigin="anonymous"></script> </head> <body hx-ext="preload"> ...未压缩版本同样可用:https://cdn.jsdelivr.net/npm/htmx-ext-preload/dist/preload.js。
方式二:拷贝到项目本地
CDN 虽然简单,但在生产环境中你可能更希望把脚本托管在自己域名下。可以从https://cdn.jsdelivr.net/npm/htmx-ext-preload下载扩展文件,放入项目合适的目录,再通过<script>标签按需引入。扩展源码也可以在仓库 dist/ext/preload.js 中直接查看。
方式三:npm 安装(适合打包构建)
npm install htmx-ext-preload安装后,需要借助打包工具(如 Webpack、Rollup)把node_modules/htmx-ext-preload/dist/preload.js(或.min.js)与node_modules/htmx.org/dist/htmx.js核心库以及项目代码一起打包。典型做法是:
import 'htmx.org'; import 'htmx-ext-preload';三、基本用法:给链接和 hx-get 元素打上 preload 标记
启用扩展只需在任意元素上设置hx-ext="preload"(hx-ext会被所有子元素继承),然后给想要预加载的<a href>和hx-get元素添加preload属性。默认情况下,资源在mousedown(鼠标按下)事件开始的一瞬间被加载,这通常能为服务器争取约 100–200ms 的响应时间优势。
<body hx-ext="preload"> <h1>会生效的场景</h1> <a href="/server/1" preload>将以标准 XMLHttpRequest() 和默认选项被请求</a> <button hx-get="/server/2" preload>将携带额外 htmx 请求头被请求</button> <h1>不会生效的场景</h1> <a href="/server/3">因为没有显式 preload 属性,不会被预加载</a> <a hx-post="/server/4" preload>因为是 HX-POST 事务,不会被预加载</a> </body>所有预加载请求都会附带一个额外的请求头"HX-Preloaded": "true",服务端可以据此识别请求是否来自预加载,从而决定缓存策略或日志统计。
从 dist/ext/preload.js 的实现可以看到两种请求路径的差异:
- 对带
hx-get(或data-hx-get)的元素,扩展调用 htmx 内置的htmx.ajax("GET", ...),因此请求会携带与其他 htmx 请求一致的请求头(如HX-Request); - 对普通
<a href>,扩展直接使用XMLHttpRequest发起标准 GET 请求。
四、属性继承:一次性预加载整片区域
如果页面中有一组链接都需要预加载,不必逐个添加preload属性,把它加在包含这些链接的顶层元素上即可,所有后代链接都会继承生效。但要注意:继承意味着可能预加载大量你用不到的资源,白白浪费带宽,务必克制。
<body hx-ext="preload"> <ul preload> <li><a href="/server/1">因为上层节点带 preload 属性,会被预加载</a> <li><a href="/server/2">同样会被预加载</a> <li><a href="/server/3">这个也会被预加载</a> </ul> </body>这一行为的底层逻辑在 dist/ext/preload.js:扩展遍历所有带[preload]属性的节点,对其自身调用init,再对其内部所有a, [hx-get], [data-hx-get]后代元素逐个调用init,从而完成整片区域的初始化。
五、预加载表单
preload扩展也能预加载部分表单元素,前提是表单带有hx-get属性或使用method="get"。preload属性可以加在表单上,也可以加在选中的个别元素上。目前支持预加载的表单元素及行为如下:
| 表单元素 | 预加载行为 |
|---|---|
<input type="radio"> | 按"该单选按钮被点击且表单已提交"的方式预加载 |
<input type="checkbox"> | 按"该复选框被勾选且表单已提交"的方式预加载 |
<input type="checkbox" checked> | 按"该复选框被取消勾选且表单已提交"的方式预加载 |
<select> | 发出多次预加载请求,模拟每个未选中选项分别被选中并提交表单 |
<input type="submit"> | 按"表单已提交"的方式预加载 |
六、级联预加载链接图片
页面(或页面片段)被预加载之后,扩展还可以顺带预加载其中引用的图片资源。需要说明的是,它不会加载或执行预加载 HTML 中链接或内嵌的 JavaScript 与 CSS 内容。开启图片级联预加载使用如下语法:
<div hx-ext="preload"> <a href="/my-next-page" preload="mouseover" preload-images="true">Next Page</a> </div>实现上,扩展在请求成功回调的done函数中检测preload-images属性是否为"true",若是则创建一个临时的div并写入返回的 HTML,借助浏览器解析器自动加载其中引用的图片资源,见 dist/ext/preload.js。
七、四种触发模式(配置详解)
扩展的默认值旨在平衡"用户感知性能"与"服务器负载"。作为开发者,你可以通过preload属性的取值自定义触发时机,主要有以下四种模式。
7.1preload="mousedown"(默认)
默认行为:用户按下鼠标左键的一瞬间开始加载资源。这是一个保守的设置——用户按下鼠标基本意味着确实打算点击这个链接。由于一次完整的点击事件通常需要 100–200ms 才结束,这个设置已经能让服务器比常规点击多出显著的响应时间余量。
<a href="/server/1" preload="mousedown">用户在开始点击时,这个链接就会被预加载</a>7.2preload="mouseover"
更激进的方案:用户鼠标悬停在链接上时就触发预加载。为防止用户滚动或扫过一长串元素时触发大量请求,该模式内置了100ms 延迟——如果鼠标在这 100ms 内离开了元素,资源不会被预加载。典型用户点击前会在链接上悬停数百毫秒,因此该模式比mousedown能给服务器更充足的响应时间。但也请注意,悬停预加载更容易产生不必要的请求,增加服务器负载。
<a href="/server/1" preload="mouseover">鼠标在其上停留超过 100ms 时,此链接被预加载</a>从 dist/ext/preload.js 可以看到mouseover的完整处理逻辑:监听mouseover事件并设置 100ms 的window.setTimeout延迟触发;同时监听mouseout,一旦鼠标离开且节点处于READY状态,立即把状态置回PAUSE,阻止加载。
7.3preload="custom-event-name":监听任意自定义事件
preload可以监听系统内的任意自定义事件来触发预加载(前提是资源尚未被浏览器缓存)。扩展自身会在每个节点初始化完成时触发一个名为preload:init的事件,利用它可以实现"页面一就绪就立即预加载"的效果:
<body hx-ext="preload"> <button hx-get="/server" preload="preload:init" hx-target="idLoadMore">Load More</button> <div id="idLoadMore"> 页面就绪时此 DIV 的内容即被预加载。 点击上面的按钮会把它交换进 DOM。 </div> </body>preload:init事件由扩展在节点初始化末尾调用htmx.trigger(node, "preload:init")主动触发,见 dist/ext/preload.js;而htmx.trigger是 htmx 核心提供的事件触发 API,定义于 src/htmx.js,它会同步分发事件并依次调用相关扩展的onEvent钩子。
7.4preload="always":持续预加载
默认情况下,每个元素只会被预加载一次(节点会被标记为DONE状态)。如果你希望某个元素被反复预加载,可以添加preload="always"。这在hx-target指向的不是元素本身时很有用,例如上例中按钮的目标是外部 DIV,每次都希望重新拉取内容。该属性还可以与其他配置组合使用,例如preload="always mouseover"。
在实现中,always标记会被解析出来并写入node.preloadAlways;加载完成回调done只有在该标记为假时才会把节点状态置为DONE,从而允许下次再次触发加载,见 dist/ext/preload.js 与 dist/ext/preload.js。
八、触摸设备适配:touchstart 即时触发
为适配触屏设备,只要指定了mouseover或mousedown触发器,扩展就会额外注册一个touchstart事件处理器。它没有等待时间,用户一触屏就立即触发预加载,可以省去 Android 上约 300ms、iOS 上约 450ms 的点击延迟等待。对应代码见 dist/ext/preload.js 中的switch (on)分支。
九、使用限制与缓存前提
使用preload扩展前,请确认以下边界条件:
- 必须显式标记:链接必须带
preload属性,或其祖先节点带preload属性,否则不会被预加载。 - 仅限 GET 事务:只有
GET事务(包括<a href>和hx-get)能被预加载。遵循 REST 原则,GET 被认为不会对资源产生显著变更;而可能产生变更的事务(如POST、PUT、DELETE)在任何情况下都不会被预加载——扩展初始化时只处理带href/hx-get/data-hx-get的节点,见 dist/ext/preload.js。 - mouseover 有 100ms 等待期:监听
mouseover时,扩展等待 100ms 才下载资源;若鼠标在此之前离开,则不预加载。 - 缓存取决于响应头:预加载的响应能否被浏览器缓存,取决于响应头是否允许。例如
Cache-Control: private, max-age=60允许浏览器缓存该响应,而Cache-Control: no-cache则禁止缓存。因此,要让预加载真正生效,服务端应针对 GET 资源返回允许缓存的响应头。
十、扩展在 htmx 体系中的定位
在 htmx 的扩展体系中,preload属于官方支持的 core extensions 之一。htmx 核心通过htmx.defineExtension(name, extension)将扩展注册进全局注册表(src/htmx.js),并在派发事件时通过withExtensions遍历当前元素可用的扩展、逐一调用其onEvent钩子(src/htmx.js)。hx-ext属性支持逗号分隔的多个扩展名,也支持ignore:extensionName语法在局部禁用父级启用的扩展,详见 www/content/attributes/hx-ext.md。
需要理解的是:扩展机制把新特性从核心库中剥离,让 htmx 核心专注于其"泛化超媒体控件"的主职,而preload这样的性能增强能力则按需加载、按域启用。
十一、设计灵感与延伸阅读
preload扩展的行为设计受到 Alexandre Dieulot 开发的 InstantClick(MIT 许可)启发。InstantClick 的核心理念正是利用mouseover/mousedown提前拉取页面。若要在项目中使用本扩展,请先阅读 htmx 扩展总览 www/content/extensions/_index.md 了解扩展分类与注册机制,再结合本文配置项落地。调试时可以在浏览器开发者工具的 Network 面板中观察带HX-Preloaded: true请求头的请求,确认预加载是否按预期触发。
- 前端
【免费下载链接】htmx
htmx - high power tools for HTML
相关推荐
htmx 懒加载实战:利用 hx-trigger="load" 实现页面元素按需加载
htmx 懒加载实战:利用 hx trigger="load" 实现页面元素按需加载 导读 本文基于 htmx 官方示例 lazy load.md https:
前端TTime OCR功能深度解析:从截图到文字识别的完整流程
TTime OCR功能深度解析:从截图到文字识别的完整流程 TTime是一款简洁、高效、高颜值的输入、截图、划词翻译软件,其OCR文字识别功能能够帮助用户快速将
桌面应用群晖 NAS 如何用 Docker 部署 go2rtc,把 UniFi Protect 摄像头 RTSP 流一次转接出来
群晖 NAS 如何用 Docker 部署 go2rtc,把 UniFi Protect 摄像头 RTSP 流一次转接出来 UniFi Protect 的 RTS
前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考