アップデート
キーンの回答と、密接に関連する質問に対するccprojの回答を参照してください。これにはありますが、テキストとして属性をisEqualNode
比較するため、同じクラスのセットまたは同じスタイルプロパティのセットを異なる順序で使用すると、ノードは同等ではないと見なされます。ccprogの答えはそれを処理します。class
style
元の回答
(完全で、ほとんどテストされておらず、確かにリファクタリングされていないオフザカフソリューションについては、以下を参照してください。しかし、最初に、その断片。)
それらの比較innerHTML
は簡単です。
if (divs[0].innerHTML === divs[1].innerHTML)
// or if you prefer using jQuery
if (divs.html() === $(divs[1]).html()) // The first one will just be the HTML from div 0
...ただし、これら2つの要素が基準に従って同等であるかどうかを自問する必要があります。
<div><span class="foo" data-x="bar">x</span></div>
<div><span data-x="bar" class="foo">x</span></div>
...それらinnerHTML
は異なるため(少なくともChromeでは、すべてではないにしてもほとんどのブラウザで疑わしい)。(詳細は以下をご覧ください。)
次に、それらのすべての属性を比較する必要があります。私の知る限り、jQueryは属性を列挙する手段を提供しませんが、DOMは次のことを提供します。
function getAttributeNames(node) {
var index, rv, attrs;
rv = [];
attrs = node.attributes;
for (index = 0; index < attrs.length; ++index) {
rv.push(attrs[index].nodeName);
}
rv.sort();
return rv;
}
それで
var names = [getAttributeNames(div[0]), getAttributeNames(div[1])];
if (names[0].length === names[1].length) {
// Same number, loop through and compare names and values
...
}
上記の配列を並べ替えることにより、「同等」の定義では属性の順序は重要ではないと想定していることに注意してください。このテストを実行すると、ブラウザごとに異なる結果が得られるため、保存されていないように見えるため、そうなることを願っています。innerHTML
その場合、要素自体の属性の順序が重要でない場合は、おそらく子孫要素の属性の順序が重要ではないため、質問に戻る必要があります。その場合は、同等の定義に従って子孫をチェックし、まったく使用innerHTML
しない再帰関数が必要になります。
次に、この後続の質問によって提起された懸念があります。要素が異なるが同等のstyle
属性を持っている場合はどうなりますか?例えば:
<div id="a" style="color: red; font-size: 28px">TEST A</div>
<div id="b" style="font-size: 28px; color: red">TEST B</div>
そこでの私の答えstyle
は、次のように要素のオブジェクトのコンテンツをループすることによってそれに対処します。
const astyle = div[0].style;
const bstyle = div[1].style;
const rexDigitsOnly = /^\d+$/;
for (const key of Object.keys(astyle)) {
if (!rexDigitsOnly.test(key) && astyle[key] !== bstyle[key]) {
// Not equivalent, stop
}
}
// Equivalent
悲しいことに、私がその答えで言うように:
少なくとも一部のブラウザでは、(一方が持っていcolor: red
てもう一方が持っているcolor: #ff0000
)場合、上記は失敗することに注意してください。スタイルプロパティが文字列値を使用する場合、通常、正規化ではなく、指定された方法で値を取得するためです。getComputedStyle
代わりに計算された(ish)値を取得するために使用できますが、CSSの適用性に関する問題が発生します。まったくgetComputedStyle
同じマークアップを持つ2つの要素は、DOM内の場所と、それらに適用されるCSSのために、異なる値を持つ可能性があります。結果。またgetComputedStyle
、ドキュメントに含まれていないノードでは機能しないため、ノードのクローンを作成してその問題を除外することはできません。
しかし、あなたはあなたの基準に従って2つの要素を比較するために上記の部分から何かをまとめることができるはずです。
さらに探索する:
不思議なことにその質問に興味があったので、しばらくそれを見て回って、次のことを思いついた。ほとんどテストされておらず、リファクタリングなどを使用できますが、ほとんどの場合、そこに到達するはずです。繰り返しになりますが、属性の順序は重要ではないと思います。以下は、テキストのわずかな違いでも重要であると想定しています。
function getAttributeNames(node) {
var index, rv, attrs;
rv = [];
attrs = node.attributes;
for (index = 0; index < attrs.length; ++index) {
rv.push(attrs[index].nodeName);
}
rv.sort();
return rv;
}
function equivElms(elm1, elm2) {
var attrs1, attrs2, name, node1, node2;
// Compare attributes without order sensitivity
attrs1 = getAttributeNames(elm1);
attrs2 = getAttributeNames(elm2);
if (attrs1.join(",") !== attrs2.join(",")) {
display("Found nodes with different sets of attributes; not equiv");
return false;
}
// ...and values
// unless you want to compare DOM0 event handlers
// (onclick="...")
for (index = 0; index < attrs1.length; ++index) {
name = attrs1[index];
if (elm1.getAttribute(name) !== elm2.getAttribute(name)) {
display("Found nodes with mis-matched values for attribute '" + name + "'; not equiv");
return false;
}
}
// Walk the children
for (node1 = elm1.firstChild, node2 = elm2.firstChild;
node1 && node2;
node1 = node1.nextSibling, node2 = node2.nextSibling) {
if (node1.nodeType !== node2.nodeType) {
display("Found nodes of different types; not equiv");
return false;
}
if (node1.nodeType === 1) { // Element
if (!equivElms(node1, node2)) {
return false;
}
}
else if (node1.nodeValue !== node2.nodeValue) {
display("Found nodes with mis-matched nodeValues; not equiv");
return false;
}
}
if (node1 || node2) {
// One of the elements had more nodes than the other
display("Found more children of one element than the other; not equivalent");
return false;
}
// Seem the same
return true;
}
実例: