JS中如何正确克隆<template>内容,解决获取firstChild为文本节点的问题
问题原因
模板标签内的换行、缩进空格会被浏览器解析为文本节点,你调用cloneNode(true)后拿到的文档片段的第一个子节点是<li>标签前的空白文本节点,自然不存在id、innerText这类元素属性,和克隆操作本身无关。
可直接落地的解决方案
方案1:使用选择器定位元素(最稳妥,不受模板格式影响)
直接通过标签名/类名从克隆的文档片段中匹配目标元素,不用依赖节点顺序,修改代码如下:
createTaskHtml(content, status, id){ const template = document.getElementById("li-temp").content.cloneNode(true); // 用querySelector直接定位元素,避免文本节点干扰 const li = template.querySelector('li'); const deleteButton = template.querySelector('.delete-item-button'); li.id = id; li.innerText = content; if (status === "done"){ li.classList.add("todo-item__done"); deleteButton.classList.remove("delete-item-button-not-displayed"); this.setListener(deleteButton); } // 注意:原代码仅返回li会丢失按钮,你可以直接返回整个克隆的文档片段,或者把按钮插入到li内部再返回li return template; }
方案2:移除模板内的空白字符
把模板内容的换行、缩进全部删掉,避免生成文本节点,修改模板代码如下:
<template id="li-temp"><li class="todo-item__undone"></li><button class="delete-item-button delete-item-button-not-displayed">✘</button></template>
修改后原有firstChild、lastChild的逻辑可以正常运行,但后续修改模板内容时如果再次加入换行缩进会重新触发问题,稳定性不如方案1。
方案3:过滤文本节点
遍历克隆后的节点列表,只保留元素节点:
const elements = [...template.childNodes].filter(node => node.nodeType === Node.ELEMENT_NODE); const li = elements[0]; const deleteButton = elements[1];
内容的提问来源于stack exchange,提问作者Vadim Vedenin
相关产品推荐
相关产品推荐

