:跨父节点重排页面时无缝保留视频播放状态)
前端【免费下载链接】htmxhtmx - high power tools for HTML项目地址https://gitcode.com/GitHub_Trending/ht/htmx点击查看免费下载htmx 在hx-preserve属性中集成了实验性的 [moveBefore()DOM API]当浏览器支持时它可以让你在通过 htmx 合并新内容、彻底改变页面布局的同时将标记为hx-preserve的元素如正在播放的视频、保持焦点的输入框原封不动地“搬移”到新的父节点下播放状态、焦点等全部保留。本文以仓库中的 move-before 示例 为主线讲解如何在 Chrome Canary 中开启该 API、演示其效果、剖析 src/htmx.js 中的底层实现并给出完整的hx-preserve使用要点、回退逻辑与测试依据。背景为什么需要 moveBefore()在传统的 Web 开发中当一个 DOM 元素被“reparenting”即改变其父节点时浏览器会重置该元素的状态正在播放的video/iframe会停止播放输入框的焦点与光标位置会丢失。这意味着如果你希望在一次 AJAX 交换后彻底改变页面的布局结构比如把视频从div里挪进figure里几乎不可能不打断用户的观看体验。现有的替代方案是 DOM morphing变形例如 morphdom 扩展 所采用的“新页面结构与旧页面足够接近”的策略——它通过逐节点对比来尽力保留元素。但这要求新页面的结构不能有大的变动否则像视频这类元素仍然无法被保留。htmx 官方文档在 hx-preserve 属性说明 中也明确指出某些元素如input typetext的焦点和光标位置、iframe 或某些类型的视频在常规保留策略下无法被完整保留因此推荐 morphdom 做更细致的 DOM 对账。moveBefore()为这一问题提供了根本解法它允许开发者在一次原子操作中把元素从旧父节点移动到新父节点而不触发布局重置从而完全改变页面布局的同时保留元素的播放状态、焦点等。htmx 在hx-preserve功能中优先使用该 API如果可用。在 Chrome Canary 中启用 moveBefore()moveBefore()目前仍是实验性 APIWHATWG DOM 规范提案 issue #1255该示例的演示需要安装Chrome Canary并手动开启对应 flag安装 Chrome Canary 并打开浏览器在地址栏导航到chrome://flags/#atomic-move将Atomic DOM move标志设置为Enabled重启浏览器使配置生效。开启后htmx 便会在hx-preserve功能中自动检测并使用moveBefore()API详见下文源码分析。如果你在 Chrome 稳定版或尚不支持该 API 的浏览器中运行htmx 会自动回退到常规的replaceChild保留策略功能依然可用只是无法实现“跨父节点搬移且不重置状态”。演示效果从div到figure的布局切换仓库中的 move-before 示例首页 展示了这一能力的核心场景页面中嵌入了一个 YouTube iframe它位于一个div内并带有hx-preservetrue和固定的idrick-rolldiv classcenter iframe hx-preservetrue idrick-roll width617 height351 srchttps://www.youtube.com/embed/dQw4w9WgXcQ titleRick Astley - Never Gonna Give You Up (Official Music Video) frameborder0 allowaccelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share referrerpolicystrict-origin-when-cross-origin allowfullscreen/iframe div a hx-boosttrue href/examples/move-before/detailsView Details rarr;/a /div /div点击hx-boosttrue的View Details链接后页面通过 hx-boost 发起整页级别的 AJAX 交换过渡到 details 页面。在 details 页面中响应里有一个相同idrick-roll的 iframe但它被嵌入在figure元素中figure iframe hx-preservetrue idrick-roll width617 height351 srchttps://www.youtube.com/embed/dQw4w9WgXcQ titleRick Astley - Never Gonna Give You Up (Official Music Video) frameborder0 allowaccelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share referrerpolicystrict-origin-when-cross-origin allowfullscreen/iframe figcaptionA Classic Rick Roll/figcaption /figure在没有moveBefore()的情况下这种“从div的子节点变成figure的子节点”的 reparenting 必然导致视频重置。而开启该 API 后视频会持续播放并且点击浏览器返回键回到首页后依然可以继续观看。这正是hx-preserve与moveBefore()组合带来的核心价值服务器端完全掌控布局结构客户端无缝保留有状态元素。源码剖析htmx 如何在 hx-preserve 中集成 moveBefore()htmx 对moveBefore()的集成位于 src/htmx.js 的handlePreservedElements函数中。当新响应中包含[hx-preserve]/[data-hx-preserve]元素时htmx 会读取该元素的id并在当前文档中查找同 id 的现有元素若找到且该元素或其父节点支持moveBeforeAPI则创建一个隐藏的“储藏间pantry”容器let pantry find(#--htmx-preserve-pantry--) if (pantry null) { getDocument().body.insertAdjacentHTML(afterend, div id--htmx-preserve-pantry--/div) pantry find(#--htmx-preserve-pantry--) }通过pantry.moveBefore(existingElement, null)把现有元素原子性地“暂存”到 pantry 中而非销毁随后继续执行交换逻辑交换完成后在 restorePreservedElements 中把元素从 pantry 搬回新文档中的目标位置existingElement.parentNode.moveBefore(preservedElt, existingElement) existingElement.remove()也就是说htmx 用moveBefore将元素从旧父节点移动到临时容器再移动到新的父节点全程都是“原子移动”而非“删除重建”因此视频播放、焦点等内部状态得以保留。回退逻辑如果当前环境不支持moveBefore例如preservedElt.moveBefore为undefinedhtmx 会退回到传统方案——用现有元素直接替换响应中的占位节点preservedElt.parentNode.replaceChild(existingElement, preservedElt)此时元素仍能按id被保留但无法跨父节点移动而不重置状态。这一分支同样体现在 测试用例 中当把fragment.firstChild.moveBefore置为undefined后handlePreservedElements会把旧内容直接复制进 fragment模拟无 API 环境下的回退行为。hx-preserve 使用要点根据 hx-preserve 属性文档使用时需要遵守以下规则必须设置不变的id元素按id被保留响应中必须包含相同id的元素响应中该元素的类型和其他属性会被忽略写法上既可以使用hx-preservetrue也可以直接用布尔属性hx-preservehx-preserve不继承只在显式标记的元素上生效与 History Support 配合时浏览器后退/前进等操作也会保留hx-preserve元素的状态避免在可能包含hx-preserve元素的请求上使用hx-swapnone以免元素丢失hx-preserve元素可以在 partial 或 OOB 响应中被重新定位——例如把视频从当前位置搬到新位置div idnew_location Just relocated the video here div idvideo hx-preserve/div /div也可以用在 hx-swap-oob 元素的内部内容中div idnotify hx-swap-oobtrue Notification updated but keep the same retain div idretain hx-preserve/div /div值得注意的是常规保留策略下仍有一些元素无法被完整保留如input typetext的焦点与光标位置、iframe 或某些视频moveBefore()正是为攻克这类场景而生的增强路径。测试与手动验证仓库为hx-preserve提供了完善的自动化测试test/attributes/hx-preserve.js覆盖了以下关键行为基本响应处理响应中带hx-preserve的元素内容保持为旧内容其他元素被替换为新内容响应中不存在旧元素时直接插入新内容当保留元素位于hx-select选区之外时不被交换当保留元素位于hx-swap-oob或hx-select-oob交换中时不被交换OOB 交换将保留元素原封不动地搬移到新位置旧位置清空、新位置收到完整旧内容moveBefore缺失时的回退复制行为。此外仓库还提供了可在真实浏览器中体验的 手动测试入口页面提供两个按钮分别通过hx-get加载 video1.htmliframe 直接位于顶层和 video2.htmliframe 被嵌入在section idthe-video中目标均为#video-container并通过hx-push-urltrue保持 URL 与历史同步。两页中的 iframe 拥有相同的idrick-roll与hx-preservetrue配合moveBefore()即可实现在两种完全不同的布局间切换且视频不中断。在 Chrome Canary 中打开该入口文件即可复现示例页面的完整效果。局限与注意事项moveBefore()目前仍是实验性 API仅在 Chrome Canary 中通过chrome://flags/#atomic-move开启 Atomic DOM move 后才可用请勿在生产环境将其作为硬性依赖在支持该 API 的浏览器中htmx 会自动优先使用moveBefore()在不支持的浏览器中会自动回退到replaceChild保留策略功能不失效但跨父节点搬移时的状态保留能力受限若你的目标是“仅小范围微调 DOM 而不改变布局”morphdom 扩展仍是更成熟的方案moveBefore()的价值体现在需要彻底改变页面布局、同时又要保留视频/焦点等有状态元素的场景。总之hx-preservemoveBefore()为 htmx 开发者打开了一类全新的可能性让服务端自由地重新编排页面结构而客户端依然能为用户保持流畅、不中断的体验。你可以直接在本仓库的 move-before 示例 与 手动测试 中验证这一能力。赞分享前端【免费下载链接】htmxhtmx - high power tools for HTML项目地址https://gitcode.com/GitHub_Trending/ht/htmx点击查看免费下载相关推荐Pwndbg 反汇编注解Instruction Annotations机制解析Capstone 静态分析与 Unicorn 模拟增强实战Pwndbg 反汇编注解Instruction Annotations机制解析Capstone 静态分析与 Unicorn 模拟增强实战 导读 Pwndb前端htmx hx-preserve 属性完全指南如何在 HTML 替换中保持元素状态不变htmx hx preserve 属性完全指南如何在 HTML 替换中保持元素状态不变 hx preserve 是 htmx 中用于在 DOM 替换swap前端Brightness ControllerLinux多显示器亮度与色温控制的终极指南Brightness ControllerLinux多显示器亮度与色温控制的终极指南 你是否曾经在Linux系统中为多显示器亮度调节而烦恼特别是当你连接了外桌面应用上一篇GoMock自定义匹配器终极指南从原理到实战完全掌握下一篇beautiful-docs中的云服务文档Digital Ocean与Linode指南解析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考