Ozg*_*gur 35 javascript jquery
用户在HTML页面中选择两个或多个元素.我想要完成的是找到那些元素的共同祖先(如果以前没有找到,那么身体节点将是共同的祖先)?
PS:它可以通过XPath实现,但对我来说它不是一个更好的选择.也可以通过css选择器解析找到它,但我认为它是一个脏方法(?)
谢谢.
ben*_*les 67
这是一个更高效的纯JavaScript版本.
function parents(node) {
var nodes = [node]
for (; node; node = node.parentNode) {
nodes.unshift(node)
}
return nodes
}
function commonAncestor(node1, node2) {
var parents1 = parents(node1)
var parents2 = parents(node2)
if (parents1[0] != parents2[0]) throw "No common ancestor!"
for (var i = 0; i < parents1.length; i++) {
if (parents1[i] != parents2[i]) return parents1[i - 1]
}
}
Run Code Online (Sandbox Code Playgroud)
lon*_*day 44
涉及手动遍历祖先元素的解决方案远比必要复杂得多.您不需要手动执行循环.获取一个元素的所有祖先元素parents()
,将其减少为包含第二个元素的元素has()
,然后获取第一个祖先first()
.
var a = $('#a'),
b = $('#b'),
closestCommonAncestor = a.parents().has(b).first();
Run Code Online (Sandbox Code Playgroud)
这里还有一个纯粹的使用方法element.compareDocumentPosition()
和element.contains()
,前者是一个标准的方法,而后者是通过排除火狐绝大多数主流浏览器所支持的方法:
function getCommonAncestor(node1, node2) {
var method = "contains" in node1 ? "contains" : "compareDocumentPosition",
test = method === "contains" ? 1 : 0x10;
while (node1 = node1.parentNode) {
if ((node1[method](node2) & test) === test)
return node1;
}
return null;
}
Run Code Online (Sandbox Code Playgroud)
工作演示:http://jsfiddle.net/3FaRr/(使用lonesomeday的测试用例)
这应该或多或少地尽可能高效,因为它是纯DOM并且只有一个循环.
再看看这个问题,我注意到"两个或更多"要求中的"或更多"部分被答案忽略了.所以我决定稍微调整一下以允许指定任意数量的节点:
function getCommonAncestor(node1 /*, node2, node3, ... nodeN */) {
if (arguments.length < 2)
throw new Error("getCommonAncestor: not enough parameters");
var i,
method = "contains" in node1 ? "contains" : "compareDocumentPosition",
test = method === "contains" ? 1 : 0x0010,
nodes = [].slice.call(arguments, 1);
rocking:
while (node1 = node1.parentNode) {
i = nodes.length;
while (i--) {
if ((node1[method](nodes[i]) & test) !== test)
continue rocking;
}
return node1;
}
return null;
}
Run Code Online (Sandbox Code Playgroud)
试试这个:
function get_common_ancestor(a, b)
{
$parentsa = $(a).parents();
$parentsb = $(b).parents();
var found = null;
$parentsa.each(function() {
var thisa = this;
$parentsb.each(function() {
if (thisa == this)
{
found = this;
return false;
}
});
if (found) return false;
});
return found;
}
Run Code Online (Sandbox Code Playgroud)
像这样使用它:
var el = get_common_ancestor("#id_of_one_element", "#id_of_another_element");
Run Code Online (Sandbox Code Playgroud)
这只是很快就嘎嘎作响,但它应该有效.如果你想要稍微不同的东西(例如jQuery对象返回而不是DOM元素,DOM元素作为参数而不是ID等),应该很容易修改
小智 5
上面提到的Range API 的commonAncestorContainer属性,以及它的selectNode,使得这是一个明智的选择.
在Firefox的Scratchpad或类似的编辑器中运行("显示")此代码:
var range = document.createRange();
var nodes = [document.head, document.body]; // or any other set of nodes
nodes.forEach(range.selectNode, range);
range.commonAncestorContainer;
Run Code Online (Sandbox Code Playgroud)
请注意,IE 8或更低版本不支持这两种API.
这不再需要太多代码来解决:
脚步:
代码:
function getLowestCommonParent(node_a, node_b) {
while (node_a = node_a.parentElement) {
if (node_a.contains(node_b)) {
return node_a;
}
}
return null;
}
Run Code Online (Sandbox Code Playgroud)