Javascript 如何比较两个 HTML 元素
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10679762/
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
How to compare two HTML elements
提问by sachinjain024
How can we compare two HTML elements whether they are identical or not ?
我们如何比较两个 HTML 元素是否相同?
I tried this thing but no luck
我试过这件事,但没有运气
<div class="a"> Hi this is sachin tendulkar </div>
<div class="a"> Hi this is sachin tendulkar </div>
And then on button click, I call a function check()
然后单击按钮,我调用函数 check()
var divs = $(".a");
alert(divs.length); // Shows 2 here which is correct
if (divs.get(0) == divs.get(1)) alert("Same");
But this is not working. Everything is same in two divs. Apart from this How can we compare whether two HTML elements are completely idential or not. Including their innerHTML, className, Id, and their attributes.
但这是行不通的。两个 div 中的所有内容都相同。除此之外,我们如何比较两个 HTML 元素是否完全相同。包括它们的innerHTML、className、Id 和它们的属性。
Is this doable ?
这是可行的吗?
Actually, I have two HTML documents and I want to remove the identical content from both of them So two elements can have same id.
实际上,我有两个 HTML 文档,我想从它们中删除相同的内容,因此两个元素可以具有相同的 id。
PS: Updating after Crowder's valuable comments. If we compare two elements as strings, we would not get a match as their order of attributes may vary So the only option is to iterate through each child attribute and match. I still have to figure out completely working implementation strategy.
PS:在 Crowder 提出宝贵意见后更新。如果我们将两个元素作为字符串进行比较,我们将无法获得匹配项,因为它们的属性顺序可能会有所不同,因此唯一的选择是遍历每个子属性并进行匹配。我仍然必须弄清楚完全可行的实施策略。
回答by Keen
You can use:
您可以使用:
element1.isEqualNode(element2);
In your specific example:
在您的具体示例中:
var divs = $(".a");
if ( divs.get(0).isEqualNode(divs.get(1)) ) alert("Same");
The DOM Level 3 Core Spechas all the details. Essentially this returns true of the two nodes have matching attributes, descendents, and the descendents' attributes.
在DOM 3级核心规范了所有的细节。本质上,如果两个节点具有匹配的属性、后代和后代的属性,则返回 true。
There's a similar .isSameNode() that returns true only if both elements are the same node. In your example, these are not the same nodes, but they are equal nodes.
有一个类似的 .isSameNode() 仅当两个元素是同一个节点时才返回 true。在您的示例中,这些不是相同的节点,但它们是相等的节点。
回答by T.J. Crowder
Update
更新
See Keen's answerand also ccproj's answer to a closely-related question. There's isEqualNode
for this, but it compares class
and style
attributes as text, so the same set of classes or the same set of style properties in different orders will make it think nodes aren't equivalent. ccprog's answerhandles that.
请参阅Keen 的回答以及ccproj 对一个密切相关的问题的回答。有isEqualNode
这个,但它比较class
和style
属性作为文本,所以相同的类集或不同顺序的相同样式属性集会使其认为节点不等效。ccprog 的回答解决了这个问题。
Original Answer
原答案
(See below for a complete, largely-untested, and certainly un-refactored off-the-cuff solution. But first, the bits and pieces of it.)
(有关完整的、大部分未经测试且当然未经重构的现成解决方案,请参见下文。但首先,它的点点滴滴。)
Comparing their innerHTML
is easy:
比较它们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
...although you have to ask yourself whether these two elements are equivalent according to your criteria:
...尽管根据您的标准,您必须问自己这两个元素是否等效:
<div><span class="foo" data-x="bar">x</span></div>
<div><span data-x="bar" class="foo">x</span></div>
...because their innerHTML
will be different(at least on Chrome, and I suspect on most if not all browsers). (More on that below.)
...因为它们innerHTML
会有所不同(至少在 Chrome 上,我怀疑在大多数浏览器上(如果不是所有浏览器)。(更多关于下面的内容。)
Then you need to compare all of their attributes. As far as I know, jQuery doesn't give you a means of enumerating the attributes, but the DOM does:
然后你需要比较它们的所有属性。据我所知,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;
}
Then
然后
var names = [getAttributeNames(div[0]), getAttributeNames(div[1])];
if (names[0].length === names[1].length) {
// Same number, loop through and compare names and values
...
}
Note that by sorting the arrays above, I'm assuming the order of their attributes is not significant in your definition of "equivalent." I hope that's the case, because it doesn't seem to be preserved, as I get different results from different browsers when running this test. That being the case, we have to come back to the innerHTML
question, because if the order of attributes on the elements themselves is not significant, then presumably the order of attributes on descendant elements shouldn't be significant. If that'sthe case, you'll need a recursive function that checks the descendants according to your definition of equivalent, and not use innerHTML
at all.
请注意,通过对上面的数组进行排序,我假设它们的属性顺序在您对“等效”的定义中并不重要。我希望是这样,因为它似乎没有被保留,因为我在运行这个测试时从不同的浏览器得到不同的结果。既然如此,我们必须回到innerHTML
问题上来,因为如果元素本身的属性顺序不重要,那么后代元素的属性顺序应该不重要。如果是这种情况,您将需要一个递归函数,根据您对等价的定义检查后代,而根本不使用innerHTML
。
Then there's the concern raised by this subsequent question: What if the elements have different-but-equivalent style
attributes? E.g.:
然后是随后的问题引起的关注:如果元素具有不同但等效的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>
My answer thereaddresses it by looping through the contents of the elements' style
objects, like this:
我的答案是通过循环元素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
Sadly, as I say in that answer:
可悲的是,正如我在那个答案中所说:
Note that the above will fail if (one of them has
color: red
and the other hascolor: #ff0000
), at least on some browsers, because when a style property uses a string value, usually you get the value the way it was supplied, not normalized. You could usegetComputedStyle
to get the computed (ish) value instead, but then we get into issues around CSS applicability: Two elements with exactlythe same markup can have different values fromgetComputedStyle
because of where they are in the DOM and the CSS applied to them as a result. AndgetComputedStyle
doesn't work on nodes that aren't in a document, so you can't just clone the nodes to factor out that issue.
请注意,如果(其中一个 has
color: red
另一个 hascolor: #ff0000
),至少在某些浏览器上,以上将失败,因为当样式属性使用字符串值时,通常您会按照提供的方式获取值,而不是标准化。您可以使用getComputedStyle
来获取计算的 (ish) 值,但随后我们会遇到有关 CSS 适用性的问题:具有完全相同标记的两个元素可能具有不同的值,getComputedStyle
因为它们在 DOM 中的位置以及应用于它们的 CSS 作为结果。并且getComputedStyle
不适用于不在文档中的节点,因此您不能只是克隆节点来解决该问题。
But you should be able to put something together from the pieces above to compare two elements according to your criteria.
但是您应该能够根据您的标准将上述部分中的某些内容放在一起,以比较两个元素。
More to explore:
更多探索:
The question interested me strangely, so I kicked around at it for a while, and came up with the following. It's mostly untested, could use some refactoring, etc., but it should get you most of the way there. I do, again, assume the order of attributes is not significant. The below assumes even the slightest difference in the text issignificant.
这个问题奇怪地引起了我的兴趣,所以我想了一会儿,然后想出了以下内容。它大多未经测试,可以使用一些重构等,但它应该可以帮助您完成大部分工作。我再次假设属性的顺序并不重要。以下假设即使文本中最细微的差异也是显着的。
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;
}
Live examples:
现场示例:
回答by ephemeron
Why not do it the easy way?
为什么不以简单的方式做呢?
<div id="div1"><div class="a"> Hi this is sachin tendulkar </div></div>
<div id="div2"><div class="a"> Hi this is sachin tendulkar </div></div>
if($('#div1').html() == $('#div2').html())
alert('div1 & div2 are the same');
else
alert('div1 & div2 are different');
回答by Hatter Jiang
How does this codes?
这个怎么打码?
var d1 = document.createElement("div");
d1.appendChild(divs.get(0));
var d2 = document.createElement("div");
d2.appendChild(divs.get(1));
if (d1.innerHTML == d2.innerHTML) ?