jQuery克隆template标签后无法选择子元素问题排查
问题背景
需要实现从<template>模板克隆站点模块,克隆后给class为site-container的子div设置从数据库获取的唯一站点ID,再插入到页面容器中。
基础模板结构如下:
<template id="base-site-template"> <div class="site-container"> <div class="site-minimize"> <span class="site-minimize-carat" onclick="toggleSiteShow()">▲</span> </div> <div class="site-sidenav"> <a href="#!">General</a> <a href="#!">Site Resiliency</a> <a href="#!">Site Sizing</a> <a href="#!">Leased Property</a> <a href="#!">Satellite</a> <a href="#!">Contacts</a> </div> <div class="site-bottom-buttons"> <button class="site-bottom-button get-contacts">Get contacts</button> <button class="site-bottom-button claim-site">Claim site</button> </div> </div> </template>
原有实现代码分为两部分:
- 遍历站点数据,调用克隆方法后将结果追加到页面容器
function updateNSites(data){ data["fetched-sites"].map(function(element, index){ var cloned = cloneTemplate(index); console.log(`Processing site ${index}...`); $("#fetch-n-sites-demo").append(cloned); }); }
- 克隆模板并修改目标元素id
function cloneTemplate(index){ var testClone = $("#base-site-template").clone(); var siteContainer = $("#base-site-template > div"); console.log(siteContainer.length); console.log("Num of children: " + testClone.children().length); console.log(testClone.children()[0]); siteContainer.attr("id", index); return $(siteContainer); }
运行后控制台输出异常,无法找到目标子元素:
[Console log of "siteContainer.length"] - 0 [Console log of "testClone.children().length"] - Num of children: 0 [Console log of "testClone.children()[0]"] - undefined
问题原因
核心问题是对<template>标签的特性不熟悉:<template>是HTML提供的原生模板标签,它内部的内容不会被直接渲染到DOM树,也不会作为template标签的普通子节点存在,所有模板内容都存储在标签自身的content属性中,这个属性是一个DocumentFragment(文档片段)对象。
原有代码的具体错误点:
- 直接对
<template>标签节点调用jQuery的.clone()方法,克隆的只是空的template标签本身,没有克隆内部存储的模板内容 - 选择
siteContainer时直接在全局DOM中查找#base-site-template > div,既没有在克隆的副本中查找,也因为template内容不在普通DOM树里,根本匹配不到任何元素 - 最后返回的是空的jQuery对象,插入页面也不会显示正确内容
修正方案
直接操作template的content属性完成克隆和修改即可,修正后的代码如下:
function cloneTemplate(index){ // 获取原生template元素,深克隆内部存储的模板内容片段 const templateContent = document.querySelector('#base-site-template').content.cloneNode(true); // 在克隆出的内容片段中查找目标容器 const siteContainer = templateContent.querySelector('.site-container'); // 给目标容器设置唯一id,建议加前缀避免纯数字id的兼容问题 siteContainer.id = `site-${index}`; // 返回内容片段,可直接被jQuery append 插入页面 return templateContent; } function updateNSites(data){ // 不需要返回值的场景用forEach比map更合适 data["fetched-sites"].forEach(function(element, index){ const clonedNode = cloneTemplate(index); console.log(`Processing site ${index}...`); $("#fetch-n-sites-demo").append(clonedNode); }); }
如果习惯全用jQuery实现,也可以用jQuery方式操作content节点:
function cloneTemplate(index){ const template = document.querySelector('#base-site-template'); const $clonedContent = $(template.content.cloneNode(true)); $clonedContent.find('.site-container').attr('id', `site-${index}`); return $clonedContent; }
内容的提问来源于stack exchange,提问作者Ian Murray
相关产品推荐
相关产品推荐

