Document.importNode与Node.cloneNode(真实例子)

54

11
在现代浏览器中,可能看不出区别(除了它们显然在不同的接口上定义)。从历史角度来看,在DOM中,importNode用于从不同文档复制节点,而cloneNode用于在同一文档中复制节点,但是DOM4取消了这种区别,因为这种区别没有有用的效果。 - Alohci
3个回答

32

Alohci说得对:由于网页兼容性强制浏览器在将一个节点插入到另一个文档之前隐式地执行了adoptNode(),因此两种方法的差异不大。

在将克隆节点插入新文档之前,有一个区别:通过cloneNode(original)返回的节点的所有者文档与原始节点相同,如果调用newDocument.importNode(original),则是新文档。如果使用ownerDocument或相关属性(如baseURI),可以看到这种区别。

但是,如果在原始节点所属的同一文档上调用importNode,则两种方法没有任何区别。


13

简单地说:

element.cloneNode() 用于从当前文档中克隆节点,例如,在使用阴影 DOM 时,当您附加任何 DOM 元素(如template)时。 在那里,您调用 shadowDOM.appendChild(template.content.cloneNode(true)),其中template 是在您的 HTML 中定义的<template> 的实例。在这里,您告诉 JS 从当前 DOM 中抓取元素并将其附加到阴影 DOM 中。

document.importNode() 用于从另一个文档中克隆节点,例如,在使用有自己 DOM 的<iframe>时,将来自iframe的任何元素显示到您的 DOM 中。

var frame = document.getElementsByTagName("IFRAME")[0]
var h = frame.contentWindow.document.getElementsByTagName("H1")[0];
var x = document.importNode(h);

document.adoptNode() 是另一个方法,与 importNode() 相似,但有一个区别,它会从其父 DOM 中移除原始元素。 importNode() 会复制原始元素而不移除,而 adoptNode() 会完全从其 DOM 中删除原始元素。

var frame = document.getElementsByTagName("IFRAME")[0]
var h = frame.contentWindow.document.getElementsByTagName("H1")[0];
var x = document.adoptNode(h);

4
我看到很多在线的代码示例中,使用importNode与模板内容一起,而不是使用cloneNode。 - Chris_F

6

几个月前我开始在课堂上学习JavaScript,今天我发现了这两种方法之间的一个区别。因为 Iaroslav Baranov 想要一个例子,所以在这里:

我试图克隆一个HTML模板标签及其内容,创建一本书籍的画廊(像电子商务网站上的产品列表页面)。以下是HTML代码:

<template id="modeleLivre">
<article class="livre">
  <header class="titre">${titre}</header>
  <p class="imageCouverture">
    <img src="images/${imageCouverture}">
  </p>
  <p class="auteur">${auteur}</p>
  <p class="prix">${prix} €</p>
  <p class="genre">${genre}</p>
  <input type="button" class="btn_achat" value="Ajouter au panier">
</article>

以下是我最初尝试运行的JS函数:

let template = document.getElementById("modeleLivre");

let templateClone;

for (let i = 0; i < gallery.length; i++) {
    templateClone = document.importNode(template.content, true);
    let eBook = templateClone.querySelector(".livre");
    let title = catalogue[i].getTitle();
    let coverImage = catalogue[i].getCoverImage();
    let author = catalogue[i].getAuthor();
    let price = catalogue[i].getPrice();
    let book = eBook.innerHTML;
    
    eBook.innerHTML = book.replace('${titre}', title).replace('${imageCouverture}', coverImage).replace('${auteur}', author).replace('${prix}', price);

    bookListing.appendChild(templateClone);
}

这个代码本来可以完美运行,但浏览器一直在寻找一个未知的、奇怪的图片来替换coverImage变量:

GET ../images/$%7BimageCouverture%7D | net::ERR_FILE_NOT_FOUND

解决方法

为了避免这个错误,我只需要把循环中使用importNode()的第一行代码改成如下所示:

templateClone = template.content.cloneNode(true);

解释

我不知道为什么cloneNode()不会抛出错误,而importNode()会。我唯一的猜测是,如果克隆引用和所附加的克隆在同一DOM中,则不应使用importNode()。

无论如何,如果有人能进一步解释这两种方法之间的区别,我会很高兴,但既然OP要求提供一个例子,那么这就是我的例子。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接