使用JavaScript复制元素(及其样式)

ace*_*bal 23 javascript css dom

对于我正在实现的JavaScript库,我需要克隆一个与原始元素具有完全相同的应用样式的元素.虽然我已经获得了相当不错的JavaScript知识,作为一种编程语言,在开发它时,我仍然是一个DOM脚本新手,所以任何有关如何实现这一点的建议都会非常有用(并且必须要做到这一点)不使用任何其他JavaScript库).

非常感谢你提前.

编辑:cloneNode(true)不克隆元素的计算样式.假设您有以下HTML:

<body>
  <p id="origin">This is the first paragraph.</p>
  <div id="destination">
    <p>The cloned paragraph is below:</p>
  </div>
</body>
Run Code Online (Sandbox Code Playgroud)

有些风格如:

body > p {
  font-size: 1.4em;
  font-family: Georgia;
  padding: 2em;
  background: rgb(165, 177, 33);
  color: rgb(66, 52, 49);
}
Run Code Online (Sandbox Code Playgroud)

如果您只是使用以下内容克隆元素:

var element = document.getElementById('origin');
var copy = element.cloneNode(true);
var destination = document.getElementById('destination');
destination.appendChild(copy);
Run Code Online (Sandbox Code Playgroud)

样式未克隆.

Jus*_*son 31

您不仅需要克隆,而且您可能也想要进行深度克隆.

node.cloneNode(true);
Run Code Online (Sandbox Code Playgroud)

文档在这里.

如果deep设置为false,则不会克隆任何子节点.节点包含的任何文本也不会被克隆,因为它包含在一个或多个子Text节点中.

如果深度计算结果为true,则也会复制整个子树(包括可能位于子文本节点中的文本).对于空节点(例如IMG和INPUT元素),无论deep是设置为true还是false都无关紧要,但您仍需提供值.

编辑:OP表示node.cloneNode(true)不是复制样式.这是一个简单的测试,使用jQuery和标准DOM API显示相反的(和期望的效果):

var node = $("#d1");

// Add some arbitrary styles
node.css("height", "100px"); 
node.css("border", "1px solid red");

// jQuery clone
$("body").append(node.clone(true));

// Standard DOM clone (use node[0] to get to actual DOM node)
$("body").append(node[0].cloneNode(true)); 
Run Code Online (Sandbox Code Playgroud)

结果显示在这里:http://jsbin.com/egice3/

编辑2

希望你之前提到过;)计算风格完全不同.更改CSS选择器或将该样式应用为类,您将获得一个解决方案.

编辑3

因为这个问题是合法的,我没有找到任何好的解决方案,所以让我感到困扰,想出以下内容.它不是特别优雅,但它完成了工作(仅在FF 3.5中测试).

var realStyle = function(_elem, _style) {
    var computedStyle;
    if ( typeof _elem.currentStyle != 'undefined' ) {
        computedStyle = _elem.currentStyle;
    } else {
        computedStyle = document.defaultView.getComputedStyle(_elem, null);
    }

    return _style ? computedStyle[_style] : computedStyle;
};

var copyComputedStyle = function(src, dest) {
    var s = realStyle(src);
    for ( var i in s ) {
        // Do not use `hasOwnProperty`, nothing will get copied
        if ( typeof i == "string" && i != "cssText" && !/\d/.test(i) ) {
            // The try is for setter only properties
            try {
                dest.style[i] = s[i];
                // `fontSize` comes before `font` If `font` is empty, `fontSize` gets
                // overwritten.  So make sure to reset this property. (hackyhackhack)
                // Other properties may need similar treatment
                if ( i == "font" ) {
                    dest.style.fontSize = s.fontSize;
                }
            } catch (e) {}
        }
    }
};

var element = document.getElementById('origin');
var copy = element.cloneNode(true);
var destination = document.getElementById('destination');
destination.appendChild(copy);
copyComputedStyle(element, copy);
Run Code Online (Sandbox Code Playgroud)

有关更多信息和一些注意事项,请参阅PPK的文章" 获取样式".

  • 谢谢 Justing(和 S. Mark)的回复,但不幸的是,cloneNode(我用来克隆元素的)对于样式没有任何作用。这就是我的问题的关键部分:如何不仅克隆元素,而且克隆应用于它的样式。 (2认同)

Lui*_*ico 7

在研究了整个Web上的几个好的解决方案之后,我决定结合每个方面的所有最佳方面,并提出解决方案。

我将解决方案保留在简单的超快速Javascript中,以便每个人都可以转换为他们本月最新的出色JS风格。

代表来自马尼拉的香草.....


 * @problem: Sometimes .cloneNode(true) doesn't copy the styles and your are left
 * with everything copied but no styling applied to the clonedNode (it looks plain / ugly). Solution:
 * 
 * @solution: call synchronizeCssStyles to copy styles from source (src) element to
 * destination (dest) element.
 * 
 * @author: Luigi D'Amico (www.8bitplatoon.com)
 * 
 */
function synchronizeCssStyles(src, destination, recursively) {

    // if recursively = true, then we assume the src dom structure and destination dom structure are identical (ie: cloneNode was used)

    // window.getComputedStyle vs document.defaultView.getComputedStyle 
    // @TBD: also check for compatibility on IE/Edge 
    destination.style.cssText = document.defaultView.getComputedStyle(src, "").cssText;

    if (recursively) {
        var vSrcElements = src.getElementsByTagName("*");
        var vDstElements = destination.getElementsByTagName("*");

        for (var i = vSrcElements.length; i--;) {
            var vSrcElement = vSrcElements[i];
            var vDstElement = vDstElements[i];
//          console.log(i + " >> " + vSrcElement + " :: " + vDstElement);
            vDstElement.style.cssText = document.defaultView.getComputedStyle(vSrcElement, "").cssText;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)