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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1848445/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-22 21:36:07  来源:igfitidea点击:

Duplicating an element (and its style) with JavaScript

javascriptcssdom

提问by acebal

For a JavaScript library I'm implementing, I need to clone an element which has exactly the same applied style than the originalone. Although I've gained a rather decent knowledge of JavaScript, as a programming language, while developing it, I'm still a DOM scripting newbie, so any advice about how this can be achieved would be extremely helpful (and it has to be done without using any other JavaScript library).

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

Thank you very much in advance.

非常感谢您提前。

Edit: cloneNode(true)does not clone the computed style of the element. Let's say you have the following HTML:

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

And some style like:

还有一些风格,如:

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

If you just clone the element, using something like:

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

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

Styles are not cloned.

样式不会被克隆。

回答by Justin Johnson

Not only will you need to clone, but you'll probably want to do deepcloning as well.

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

node.cloneNode(true);

Documentation is here.

文档在这里

If deepis set to false, none of the child nodes are cloned. Any text that the node contains is not cloned either, as it is contained in one or more child Text nodes.

If deepevaluates to true, the whole subtree (including text that may be in child Text nodes) is copied too. For empty nodes (e.g. IMG and INPUT elements) it doesn't matter whether deep is set to true or false but you still have to provide a value.

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

如果deep评估为真,则整个子树(包括可能位于子 Text 节点中的文本)也被复制。对于空节点(例如 IMG 和 INPUT 元素),将 deep 设置为 true 还是 false 并不重要,但您仍然必须提供一个值。

Edit: OP states that node.cloneNode(true)wasn't copying styles. Here is a simple test that shows the contrary (and the desired effect) using both jQuery and the standard DOM API:

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

Results are visible here: http://jsbin.com/egice3/

结果在这里可见:http: //jsbin.com/egice3/

Edit 2

编辑 2

Wish you would have mentioned that before ;) Computed style is completelydifferent. Change your CSS selector or apply that style as a class and you'll have a solution.

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

Edit 3

编辑 3

Because this problem is a legitimate one that I didn't find any good solutions for, it bothered me enough to come up with the following. It's not particularily graceful, but it gets the job done (tested in FF 3.5 only).

因为这个问题是一个合法的问题,我没有找到任何好的解决方案,所以我很困扰,想出了以下内容。它不是特别优雅,但可以完成工作(仅在 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);

See PPK's article entitled Get Stylesfor more information and some caveats.

有关更多信息和一些注意事项,请参阅 PPK 题为“获取样式”的文章。

回答by Luigi D'Amico

After looking at a couple of good solutions across the WEB, I decided to combine all the best aspects of each and come up with this.

在浏览了 WEB 上的几个好的解决方案后,我决定结合每个解决方案的所有最佳方面并提出这个方案。

I left my solution in plain super fast Javascript, so that everybody can translate to their latest and great JS flavour of the month.

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

Representing the vanilla from manilla.....

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



 * @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;
        }
    }
}