如何复制一个元素的所有属性并将它们应用到另一个元素?

79

如何将一个元素的属性复制到另一个元素?

HTML

<select id="foo" class="bar baz" style="display:block" width="100" data-foo="bar">...</select>

<div>No attributes yet</div>

JavaScript

var $div = $('div');
var $select = $('select');

//now copy the attributes from $select to $div

2
您确定要复制 id 吗? - pimvdb
如果要复制id属性,你将会有一个重复的id - Tocco
也许您可以解释一下为什么需要这样做?可能有更好的解决方案。 - Michael Mior
不用担心,我要么不复制ID属性,要么删除重复的ID属性。 - Andrew
因为我不想手动复制每个属性时遗漏某个。而且,我不知道如何做到这一点,所以我想问一下,以便将来学习如何做到这一点。 - Andrew
12个回答

89

您可以使用本地的 Node#attributes 属性: http://jsfiddle.net/SDWHN/16/.

var $select = $("select");
var $div = $("div");

var attributes = $select.prop("attributes");

// loop through <select> attributes and apply them on <div>
$.each(attributes, function() {
    $div.attr(this.name, this.value);
});

alert($div.data("foo"));

1
作为注意事项:属性数组远非兼容。是的,它是核心,但是早期版本的IE会随意处理“核心”属性。我使用了“hackish”,但是从http://forum.jquery.com/topic/jquery-is-it-possible-to-clone-all-attributes-on-an-element-and-copy-to-a-different-type-of-element中采用了更符合悖论的方式——将节点转换为字符串表示形式,使用正则表达式更改其标记,然后将其转换回节点。然后我可以重新附加数据和事件。IE版本在复制某些属性时抛出错误(例如“implementation”属性-您知道它附加到所有标记上吗?) - Tomasz Struczyński
8
当你的变量包含对jQuery对象的引用时,在变量前添加'$'标识符是值得赞赏的。我在我目前的公司开始了这个趋势...它使得快速阅读代码变得非常容易! - Swivel
想问一个与此相关的问题。我尝试了 $something.prop('attributes') 并得到了一个带有属性的数组。其中之一是图像的 crossorigin 属性。我尝试了 $item.prop('crossorigin'),但它是未定义的,但如果我尝试 $item.prop('src'),它会给出结果。然后我尝试了 $item.attr('crossorigin'),它给出了值。.attr().prop() 有什么区别?为什么上述情况有些不同?提前致谢。 - 西門 正 Code Guy
1
@simongcc .prop 从表示元素 DOM 的底层本机 Node 对象中获取属性。.attr 获取通过编程或标记定义的 HTML 属性的值。 - Kroltan

32

ES6语法一行代码:

function cloneAttributes(target, source) {
  [...source.attributes].forEach( attr => { target.setAttribute(attr.nodeName ,attr.nodeValue) })
}

正如第一条评论中所指出的那样 - 你可能不想复制源ID属性...因此,为了方便参考,此代码将保存它作为"data-id"属性。

function cloneAttributes(target, source) {
  [...source.attributes].forEach( attr => { target.setAttribute(attr.nodeName === "id" ? 'data-id' : attr.nodeName ,attr.nodeValue) })
}

4
目前为止最佳答案。现在是2020年。 - EscapeNetscape
这是比被接受的答案更好的解决方案。它很干净,可以在纯JS和jQuery之间轻松地互换使用。 - Hybrid web dev
nodeName、nodeValue现在已被弃用。请参考https://developer.mozilla.org/ru/docs/Web/API/Attr。 - Winand

14

非常简单

function cloneAttributes(element, sourceNode) {
  let attr;
  let attributes = Array.prototype.slice.call(sourceNode.attributes);
  while(attr = attributes.pop()) {
    element.setAttribute(attr.nodeName, attr.nodeValue);
  }
}

请注意,该方法不会复制任何不必要的基本类型,它只克隆每个属性。 - Joel Cox
1
你使用 Array#slicewhile 而不是仅使用 Array#forEach,有什么原因吗? - yckart
可能是为了兼容已经不再更新的浏览器。 - Machado

11

这是在 jsfiddle 上的可用解决方案

编辑

已更新 jsfiddle。

Javascript

$(function(){
    var destination = $('#adiv').eq(0);
    var source = $('#bdiv')[0];

    for (i = 0; i < source.attributes.length; i++)
    {
        var a = source.attributes[i];
        destination.attr(a.name, a.value);
    }
});

HTML

<div id="adiv" class="aclass">A class</div>
<div id="bdiv" class="bclass">B class</div>

这是将#bdiv的属性复制到#adiv


4
你应该至少在这里发布代码的重要部分,即使只是为了防止网站 jsfiddle 不再存在,你的回答仍然能够保留。 - James Montagne
@kingjiv,感谢您的建议。 - Tocco
这似乎在IE(8)中存在问题,它发现了太多的属性(100+),当尝试设置属性时,jQuery会抛出一个成员未找到的异常。 - row1

3
您可以尝试这个方法:
function copyAttributes(from, to)
{
  $($(from)[0].attributes).
    each(function(){$(to).attr(this.nodeName, this.nodeValue);});

  return $(to);
};

返回语句允许您编写以下内容:
copyAttributes(some_element, $('<div></div>')).append(...) ...

希望这能有所帮助。

3
我们还可以尝试扩展jQuery原型 ($.fn) 对象,以提供一个新的方法,该方法可以链接到jQuery()函数。
以下是@pimvdb解决方案的扩展,提供了一个复制所有属性的函数。
使用方法如下:
 $(destinationElement).copyAllAttributes(sourceElement);

扩展函数可以这样定义:
(function ($) {

    // Define the function here
    $.fn.copyAllAttributes = function(sourceElement) {

        // 'that' contains a pointer to the destination element
        var that = this;

        // Place holder for all attributes
        var allAttributes = ($(sourceElement) && $(sourceElement).length > 0) ?
            $(sourceElement).prop("attributes") : null;

        // Iterate through attributes and add    
        if (allAttributes && $(that) && $(that).length == 1) {
            $.each(allAttributes, function() {
                // Ensure that class names are not copied but rather added
                if (this.name == "class") {
                    $(that).addClass(this.value);
                } else {
                    that.attr(this.name, this.value);
                }

            });
        }

        return that;
    }; 

})(jQuery);

一个示例可以在 http://jsfiddle.net/roeburg/Z8x8x/ 找到。

希望这能帮到你。


1
你的代码存在不必要的重复jQuery包装/初始化。请查看我的更改:http://jsfiddle.net/5eLdcya6/ - Matthias

2

2

一种非jquery解决方案:

function copy(element){
    var clone = document.createElement(element.nodeName);
    for(key in element){
        clone.setAttribute(key,element[key]);
    }
    return clone;
}

它会复制你可能不需要的方法和其他东西,但希望你不介意。这段代码很小而简单。


1
一个非常直接的解决方案是创建类似这样的内容:

const _$ = domQuery => document.querySelector(domQuery)
let div1 = _$('#div-1')
let div2 = _$('#div-2')

for(attr of div1.attributes) {
  div2.setAttribute(attr.name, attr.value);
}
.my-div {
height: 100px;
width: 100px;
}
<h1>div-1</h1>
<div atribute-test="test" class="my-div" style="background: red" id="div-1"></div>
<h1>div-2</h1>
<div id="div-2"></div>


0
自Firefox 22起,不再支持Node.attributes(其他浏览器未实现并从规范中删除)。它仅适用于Element(Element.attributes)。

1
这对 OP 来说完全不重要,他没有谈论文本或其他节点。 - Rudolf

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