简体   繁体   English

如何克隆具有自定义属性的 HTML 节点?

[英]How can I clone HTML Nodes with custom properties?

I am working on a Editor and want to clone a HTML Node with custom properties using JavaScript.我正在使用编辑器并希望使用 JavaScript 克隆具有自定义属性的 HTML 节点。 I only found a way using setAttribute() but it converts my custom attribute into a string:我只找到了一种使用 setAttribute() 的方法,但它将我的自定义属性转换为字符串:

// Using custom attributes
var html = document.createElement("div");
var obj  = {test: 123,html: html};
html.obj = obj;
var cloned = html.cloneNode(true);
console.log(cloned.obj); // returns null

// Using setAttribute
var html = document.createElement("div");
var obj  = {test: 123, html: html};
html.setAttribute("obj") = obj;
var cloned = html.cloneNode(true);
console.log(cloned.getAttribute("obj")); // returns "[object Object]"

How do I clone the html element with the object?如何使用对象克隆 html 元素?

Attributes in HTML are string values, not JavaScript Objects and JavaScript Properties. HTML中的属性是字符串值,而不是JavaScript对象和JavaScript属性。 The cloneNode operation only clones HTML intrinsics and not anything you add on top, it is not the same thing as a deep object copy. cloneNode操作仅克隆HTML内在函数而不是顶部添加的任何内容,它与深层对象副本不同。

You will need to do it manually: 您需要手动完成:

function cloneCustomNode(node) {

    var clone  node.cloneNode(); // the deep=true parameter is not fully supported, so I'm not using it
    clone.obj = node.obj; // this will copy the reference to the object, it will not perform a deep-copy clone of the 'obj' object
    return clone;
}

This can be generalised to copy any custom JavaScript properties from one object to another, excluding those already defined in the default ( defaultNode ). 这可以通用化将任何自定义JavaScript属性从一个对象复制到另一个对象,不包括那些已在默认值( defaultNode )中定义的属性。

var defaultNode = document.createElement("div");

function cloneNodeWithAdditionalProperties(node) {

    var clone  node.cloneNode();

    for(var propertyName in node) {

        if( !( propertyName in genericNode ) ) {

            clone[ propertyName ] = node[ propertyName ];
        }
    }

    return clone;
}

cloneNodeWithAdditionalProperties will run in O( n ) time because the if( x in y ) operation is a hashtable lookup with O( 1 ) complexity (where n is the number of properties). cloneNodeWithAdditionalProperties将在O( n )时间运行,因为if( x in y )操作是具有O( 1 )复杂度的哈希表查找(其中n是属性的数量)。

You could use a property of HTMLElement.dataset however the api only allows storing strings which would mean using JSON.stringify() while setting and JSON.parse() while getting arrays or objects 您可以使用HTMLElement.dataset的属性,但是api只允许存储字符串,这意味着在设置时使用JSON.stringify()和获取数组或对象时使用JSON.parse()

 var html = document.createElement("div"); var obj = {test: 123,html: html}; html.dataset.obj = JSON.stringify(obj); var cloned = html.cloneNode(true); console.log(JSON.parse(cloned.dataset.obj)); 

One approach is to use Object.keys() to iterate over the node (which is an Object) and apply the discovered properties, and their property-values, to the created node, for example: 一种方法是使用Object.keys()迭代节点(它是一个Object)并将发现的属性及其属性值应用于创建的节点,例如:

// named function to follow DRY principles;
// n: DOM node, the node to be cloned:
function customClone(n) {

  // creating a temporary element to hold the
  // cloned node:
  let temp = n.cloneNode(true);

  // Using Object.keys() to obtain an Array of
  // properties of the Object which are not
  // inherited from its prototype, and then
  // using Array.prototype.forEach() to iterate
  // over that array of properties:
  Object.keys(n).forEach(

    // using an Arrow function, here 'property' is
    // the current property of the Array of properties
    // over which we're iterating, and then we
    // explicitly assign the property-value of the
    // node that was cloned to the property-value of
    // that same property on the clone:
    property => temp[property] = n[property]
  );

  // returning the clone to the calling context:
  return temp;
}

let html = document.createElement("div"),
  obj = {
    test: 123,
    html: html
  };
html.obj = obj;

let cloned = customClone(html);
console.log(cloned.obj);

 function customClone(n) { let temp = n.cloneNode(true); Object.keys(n).forEach( property => temp[property] = n[property] ); return temp; } let html = document.createElement("div"), obj = { test: 123, html: html }; html.obj = obj; let cloned = customClone(html); console.log(cloned.obj); 

JS Fiddle demo . JS小提琴演示

References: 参考文献:

Extending the accepted answer, I created a snippet that deep clones all the childNodes as well.扩展接受的答案,我创建了一个片段,该片段也深度克隆了所有子节点。

 // Make a generic element to compare default properties const DIV = document.createElement('div'); function fullClone(n: Node) { // Clone the element without DEEP, so we can manually clone the child nodes const temp = n.cloneNode(); // Loop through all the properties for (let prop in n) { // Skip if the property also exists in the div element if (prop in DIV) { continue; } // We try/catch in case the property is readonly try { // Copy the value temp[prop] = n[prop]; } catch { // readOnly prop } } // Remove any childNodes left (text nodes) temp.childNodes.forEach(c => temp.removeChild(c)); // Deep clone all the childNodes n.childNodes.forEach(c => temp.appendChild(fullClone(c))); return temp; }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM