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

时间:2009-12-04 17:26:50

标签: 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>

还有一些风格:

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

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

var element = document.getElementById('origin');
var copy = element.cloneNode(true);
var destination = document.getElementById('destination');
destination.appendChild(copy);

未克隆样式。

3 个答案:

答案 0 :(得分:28)

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

node.cloneNode(true);

文档为here

  

如果设置为false,则不是   子节点被克隆。任何文字   节点包含未克隆   或者,因为它包含在一个或   更多子文本节点。

     

如果评估为真,那么整个   子树(包括可能在的子句)   子文本节点)也被复制。对于   空节点(例如IMG和INPUT   元素)无论是否   深度设置为真或假,但你   还是要提供一个价值。

编辑: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)); 

结果显示在此处: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);

有关更多信息和一些警告,请参阅PPK的文章Get Styles

答案 1 :(得分:6)

在通过WEB查看几个好的解决方案后,我决定将每个方面的所有最佳方面结合起来并提出这个问题。

我用简单的超快速Javascript离开了我的解决方案,这样每个人都可以翻译成他们最新的和本月最好的JS风格。

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

<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:fillViewport="true"
    android:scrollbars="vertical"
    android:background="@drawable/background_light_grey"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    android:padding="5dp"
    tools:context="**********">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:scrollbars="vertical"
        >
        <!-- lot of views, i cut them couse it was something near to 200 rows -->
    </LinearLayout>
</android.support.v4.widget.NestedScrollView>

答案 2 :(得分:0)

这些都没有为我工作,但我是根据路易吉的回答提出的。

copyStyles(source: HTMLElement, destination: HTMLElement) {

    // Get a list of all the source and destination elements
    const srcElements = <HTMLCollectionOf<HTMLElement>>source.getElementsByTagName('*');
    const dstElements = <HTMLCollectionOf<HTMLElement>>destination.getElementsByTagName('*');

    // For each element
    for (let i = srcElements.length; i--;) {
        const srcElement = srcElements[i];
        const dstElement = dstElements[i];
        const sourceElementStyles = document.defaultView.getComputedStyle(srcElement, '');
        const styleAttributeKeyNumbers = Object.keys(sourceElementStyles);

        // Copy the attribute
        for (let j = 0; j < styleAttributeKeyNumbers.length; j++) {
            const attributeKeyNumber = styleAttributeKeyNumbers[j];
            const attributeKey: string = sourceElementStyles[attributeKeyNumber];
            dstElement.style[attributeKey] = sourceElementStyles[attributeKey];
        }
    }
}