当前位置:首页 > 文章列表 > 文章 > 前端 > JavaScript HTMLTemplateElement.content 怎样重复实例化模板片段

JavaScript HTMLTemplateElement.content 怎样重复实例化模板片段

来源:17golang原创 2026-10-27 14:49:03 0浏览 收藏

重复使用 HTMLTemplateElement.content 时,应每次复制它包含的节点,再填数据并插入页面。可以使用 document.importNode(template.content, true);不要直接把 template.content 插进容器,否则会移动模板中的子节点,之后原件就可能为空。

文档入口:https://developer.mozilla.org/en-US/docs/Web/API/HTMLTemplateElement/content。下面用待办列表说明从模板定义、实例创建到事件管理的完整用法,示例未在本文环境运行。

保留模板原件,每次复制一个新片段

content 是模板内容的 DocumentFragment,不是模板内部 HTML 的字符串副本。读取属性本身不会自动复制。模板节点与片段内节点也不是普通父子关系,查找模板内部元素应从 template.content 开始。


    template 元素上的 id 用于定位唯一原件;模板内部则使用 class。复制时传入 true,表示连同后代节点一起复制,而不是只创建一个没有内容的片段外壳。

    template内容原件与两个独立DocumentFragment副本的关系
    原创静态结构图:原件的content保存模板节点,实例甲与实例乙拥有独立副本;连线表示来源关系,不表示执行时间。

    填充实例后再插入容器

    // 脚本放在上方HTML之后执行
    const template = document.getElementById("task-template");
    const list = document.getElementById("task-list");
    if (!(template instanceof HTMLTemplateElement) || !list) {
      throw new Error("模板或列表容器不存在");
    }
    function makeTask(label) {
      // 每次调用都复制完整子树,保留content原件
      const fragment = document.importNode(template.content, true);
      const item = fragment.querySelector(".task");
      const title = fragment.querySelector(".task-title");
      const remove = fragment.querySelector(".task-remove");
      if (!item || !title || !remove) {
        throw new Error("模板缺少必要元素");
      }
      title.textContent = label; // 将数据作为文本写入
      remove.addEventListener("click", () => item.remove());
      return { fragment, item };
    }
    const created = ["整理需求", "确认排期"].map(makeTask);
    for (const entry of created) {
      list.append(entry.fragment); // 移动副本中的节点,不移动模板原件
    }

    每次 makeTask 都创建新副本,任务标题和移除按钮各属于自己的 li。实例节点插入列表后,fragment 本身不会成为页面中的包裹元素;它的子节点转移到 list,片段随之变空。

    因此,需要后续更新任务时保存 item,而不是认为 entry.fragment 仍能查询到已插入的节点。返回对象中的 item 引用在移动后仍指向同一个元素。修改 item 的文字不会自动修改模板原件,也不会同步到其他副本。

    实例对象保存fragment和item以及列表内元素关系
    原创静态结构图:插入后的fragment为空,item引用指向列表内实际元素;应在实际元素上管理数据与事件。

    把事件绑定到实际元素

    深复制不会复制通过 addEventListener 注册的监听器,也不会复制 JavaScript 属性方式设置的事件处理函数。例子在创建每个副本时给按钮绑定监听器,正是为了让行为跟随真实按钮,而不是依赖模板原件上曾有的注册。

    也不要把监听器只绑定在 DocumentFragment 上,期待插入后的按钮事件继续冒泡到它:片段不是插入后节点的父元素。大量同类条目也可以在稳定的 list 容器上做事件委托,但应与逐实例绑定二选一,避免同一动作处理两次。

    // 替代方案:采用委托时,删除makeTask中按钮的addEventListener
    list.addEventListener("click", (event) => {
      if (!(event.target instanceof Element)) return;
      const button = event.target.closest(".task-remove");
      if (!button || !list.contains(button)) return;
      const item = button.closest(".task");
      // 只处理当前列表直接拥有的条目,避免嵌套列表误删
      if (item?.parentElement === list) item.remove();
    });

    上段是替代绑定方式,不应与前一段逐实例按钮监听一同启用。列表整体销毁时,按照应用的生命周期解除外部注册并释放业务缓存中保留的元素引用;复制模板本身不会替应用管理这些资源。

    处理重复标识与文档上下文

    cloneNode(true) 同样能够深复制节点,但模板 content 通常属于独立的内容文档。document.importNode 在调用文档的上下文中创建副本,涉及自定义元素时,这个差异会影响构造所使用的注册定义,因此这里选择它作为默认写法。

    如果模板内部确实需要 id,例如 label 的 for 或 aria-labelledby,应为每个实例生成唯一值,并成对更新所有引用属性。仅修改 id 而漏掉引用,可能使标签关联到其他条目。普通实例内查询优先使用 class 或 data 属性,可以减少不必要的全局标识管理。

    textContent 适合把标题当普通文本写入。模板结构固定时,不必为了插入一条标题改成拼接 HTML;若业务确实允许富文本,应单独设计可信内容来源和处理规则,不应把模板复用当作任意 HTML 输入的安全保证。

    按用途选择实例引用方式

    需求保存或使用的对象注意事项
    重复创建条目template.content原件每次重新深复制
    插入后更新条目item等实际元素引用片段插入后为空
    逐条注册行为副本中的按钮监听器不随克隆复制
    统一管理列表行为稳定的list容器不要重复启用逐条处理

    这套写法的价值在于结构和数据分开、实例之间彼此独立。DocumentFragment 并不保证所有场景都比循环直接插入更快,本文也没有性能测量;优先让所有权和调用方式容易理解。

    为什么第一次插入正常,第二次没有内容?

    先看是否直接插入了 template.content,或者反复插入同一个副本。片段的子节点会被移动,每条实例都需要新的复制。

    为什么在片段上querySelector查不到刚插入的按钮?

    按钮已经随子树进入列表,片段为空。保存按钮或条目引用,或从正确的列表实例查找。

    把deep省略可以吗?

    不要省略。要复制模板完整内容,应明确传 true;浅复制不能得到示例所需的后代结构。

    参考:模板content、importNode、cloneNode、DocumentFragment。

    版本声明
    本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
    苗圃 怎样给同批树苗建立位置与移栽记录苗圃 怎样给同批树苗建立位置与移栽记录
    上一篇
    苗圃 怎样给同批树苗建立位置与移栽记录
    钣金加工车间 怎样管理零件图纸的修订版本
    下一篇
    钣金加工车间 怎样管理零件图纸的修订版本
    查看更多
    最新文章
    查看更多
    课程推荐
    • 前端进阶之JavaScript设计模式
      前端进阶之JavaScript设计模式
      设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
      543次学习
    • GO语言核心编程课程
      GO语言核心编程课程
      本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
      516次学习
    • 简单聊聊mysql8与网络通信
      简单聊聊mysql8与网络通信
      如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
      500次学习
    • JavaScript正则表达式基础与实战
      JavaScript正则表达式基础与实战
      在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
      487次学习
    • 从零制作响应式网站—Grid布局
      从零制作响应式网站—Grid布局
      本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
      485次学习
    查看更多
    AI推荐
    • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
      PubMedQA
      深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
      735次使用
    • H2O EvalGPT:开源LLM大模型评估与排行榜工具
      H2O EvalGPT
      H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
      736次使用
    • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
      LMArena
      LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
      816次使用
    • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
      HELM
      深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
      776次使用
    • MMBench详解:多模态大模型基准测试、功能特点与使用指南
      MMBench
      MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
      611次使用
    微信登录更方便
    • 密码登录
    • 注册账号
    登录即同意 用户协议 和 隐私政策
    返回登录
    • 重置密码