【问题标题】:Cloned node isn't equal to original node (with isEqualNode)克隆节点不等于原始节点(使用 isEqualNode)
【发布时间】:2012-12-30 15:58:36
【问题描述】:

我正在管理 Javascript 中的名称列表。当您选中一个框时,您的姓名将出现在列表中。当您取消选中它时,它会被划掉。当你将盒子设置为不确定状态时,你的名字就被删除了。

我在一个隐藏的 div 中获得了当前登录用户的名称。名称是具有样式属性的跨度。

我用 isEqualNode 检查名字是否已经在列表中。当页面加载时它在列表中时,它工作正常:找到名称并在复选框选中状态更改时更新。

for(var i=0 ; i < bullet.childNodes.length ; i++) {
    var node = bullet.childNodes[i];
    if(node.className == 'crossed')
        node = node.firstChild;
    if(node.isEqualNode(document.getElementById('curUser').firstChild))
        break;
}
// if i < bullet.childNodes.length, then we found the user's name in the list

当名称不在列表中时,我克隆跨度。

var newName = document.getElementById('curUser').firstChild.cloneNode(true);
bullet.appendChild(newName);

这在视觉上有效。

但我偶然发现了一些棘手的问题:newName.isEqualNode(document.getElementById('curUser').firstChild) 是假的!因此,如果盒子状态再次改变,新添加的名称将不会被找到,并且会再次创建一个新名称。

这是 span 的样子:

<span style="font-weight: bold ; color: #003380 ;">Pikrass</span>

目前我只是让检查不那么严格(我可以只检查跨度内的文本数据,而不是依赖 isEqualNode),但我对为什么克隆节点可能与原始节点不同感兴趣, 根据 isEqualNode。

相关规格:cloneNodeisEqualNode


编辑:我用 Firefox 和 Chromium 进行了测试。 Firefox isEqualNode 返回 false,但 Chromium 返回 true。感谢 Felix 指出这一点。

【问题讨论】:

  • 哪个浏览器?它似乎在 Chrome 中工作:jsfiddle.net/WhxQP.
  • 有趣的问题。这是一个简化的示例:jsfiddle.net/QtJJb
  • 这个小提琴在 Firefox 17.x 中不起作用。
  • 所以,.clone 似乎没有复制 ID 属性,这可以解释差异。但是,在您的示例中,span 元素没有 ID 属性。它在你的实际代码中吗?
  • @Felix Kling:我建议您将其发布为答案。

标签: javascript html dom


【解决方案1】:

刚刚想通了。根据specification,isEqualNode 仅在两个元素具有相同数量的属性时才返回 true。但是如果源元素有一个 ID,它不会被复制,因为 ID 应该是唯一的,所以它的属性更少。使用类而不是 ID 可以正常工作。

标记:

<div id="withId">withId content</div>
<div class="withoutId">withoutId content</div>

JS:

function test(node) {
    var copy = node.clone(true);
    document.body.appendChild(copy);
    console.log('are equal: ' + copy.isEqualNode(node)
        + ', attributes lengths: ' + node.attributes.length + ' ' + copy.attributes.length
        + ', ids: ' + node.getAttribute('id') + ' ' + copy.getAttribute('id'));
}

test(document.getElementById('withId'));
// are equal: false, attributes lengths: 1 0, ids: withId null

test(document.getElementsByClassName('withoutId')[0]);
// are equal: true, attributes lengths: 1 1, ids: null null

http://jsfiddle.net/igorz/fxtDw/

【讨论】:

  • 为什么不应该复制id? W3 规范没有这样说,甚至 Mozilla's reference 明确指出“cloneNode() 可能导致文档中的元素 ID 重复”。
【解决方案2】:

写在这里Mozilla's reference(感谢@Bergi)

cloneNode() 返回的重复节点在添加到另一个节点时会收到一个新的 uniqueID

当您进行追加时,此时 id 可能已更改。

【讨论】:

  • 我认为只指内部uniqueID(如here),isEqualNode不应考虑
【解决方案3】:

迟到总比没有好。 :)

我无法再使用 Firefox 17 重现该问题,因此正如 cmets 中所讨论的,这可能是 Gecko 中的一个错误,随后已修复。

但是我找不到任何错误报告。我暂时将此答案标记为已接受,但如果有人能找到错误报告或对幕后发生的事情的解释,我会接受。

Bergi 的 cmets 对另外两个答案是正确的。

【讨论】:

    猜你喜欢
    • 2020-09-20
    • 1970-01-01
    • 1970-01-01
    • 2015-12-18
    • 1970-01-01
    • 1970-01-01
    • 2010-10-12
    • 2017-05-07
    • 1970-01-01
    相关资源
    最近更新 更多