javascript 如何选择最里面的元素?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4188933/
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 do I select the innermost element?
提问by sova
In jQuery, how would I descend as far as possible into the HTML tree?
在 jQuery 中,我如何尽可能地下降到 HTML 树中?
For simplicity, I only have one path going downward.
为简单起见,我只有一条向下的路径。
(related but bonus: how do I find the deepest element with multiple downward paths?)
(相关但奖励:我如何找到具有多个向下路径的最深元素?)
<html>
<table id="table0">
<tr>
<td id="cell0">
<div class"simple"> I want to change this information </div>
</td>
</tr>
</table>
</html>
I want to change the innermost HTML of the cell named cell0but I don't necessarily know the names of all the classes inside. Is it possible to select this far without knowing these names?
我想更改名为cell0的单元格最里面的 HTML,但我不一定知道里面所有类的名称。在不知道这些名称的情况下,是否可以选择这么远?
Thanks much!
非常感谢!
回答by pawel
For single path just find the element that doesn't have child nodes:
对于单个路径,只需找到没有子节点的元素:
$('body *:not(:has("*"))');
Or, in your more specific case $('#cell0 *:not(:has("*"))');
或者,在您更具体的情况下 $('#cell0 *:not(:has("*"))');
For multiple paths - what if there are multiple equally nested nodes? This solution will give you an array of all nodes with highest number of ancestors.
对于多个路径 - 如果有多个同样嵌套的节点怎么办?此解决方案将为您提供具有最高祖先数量的所有节点的数组。
var all = $('body *:not(:has("*"))'), maxDepth=0, deepest = [];
all.each( function(){
var depth = $(this).parents().length||0;
if(depth>maxDepth){
deepest = [this];
maxDepth = depth;
}
else if(depth==maxDepth){
deepest.push(this);
}
});
Again, in your situation you probably want to get to table cells' deepest elements, so you're back to a one-liner:
同样,在您的情况下,您可能想要获取表格单元格的最深元素,因此您又回到了单行模式:
$('#table0 td *:not(:has("*"))');
- this will return a jQuery object containing all the innermost child nodes of every cell in your table.
- 这将返回一个 jQuery 对象,其中包含表中每个单元格的所有最里面的子节点。
回答by Jacob
I'd do this through a single recursive function:
我会通过一个递归函数来做到这一点:
// Returns object containing depth and element
// like this: {depth: 2, element: [object]}
function findDeepestChild(parent) {
var result = {depth: 0, element: parent};
parent.children().each(
function(idx) {
var child = $(this);
var childResult = findDeepestChild(child);
if (childResult.depth + 1 > result.depth) {
result = {
depth: 1 + childResult.depth,
element: childResult.element};
}
}
);
return result;
}
回答by Pointy
Well, starting from a basis that you have no idea where this "deepest" node is, you could do something like this:
好吧,从您不知道这个“最深”节点在哪里的基础开始,您可以执行以下操作:
$.fn.deepest = function() {
var depth = 0;
this.find('*').each(function() {
var d = $(this).parents().length;
depth = Math.max(d, depth);
});
return this.find('*').filter(function() {
return this.parents().length === depth;
});
});
Then
然后
var $deepest = $('body').deepest();
would (excepting the 12 bugs probably in my code) would be a jQuery object for the set of deepest elements.
将(除了可能在我的代码中的 12 个错误)将是最深元素集的 jQuery 对象。
edit— one of my dozen bugs is that this doesn't take into account the depth of the starting node(s) - that'd be a trick to figure out. Might be better to refactor it so that it finds the deepest of the originally-selected list:
编辑- 我的十几个错误之一是这没有考虑起始节点的深度 - 这将是一个弄清楚的技巧。重构它可能会更好,以便它找到最初选择的列表中最深的:
$.fn.betterDeepest = function() {
var depth = 0;
this.each(function() {
depth = Math.max(depth, $(this).parents().length);
});
return this.filter(function() { return $(this).parents().length === depth; });
});
and to get the deepest on the page you'd do:
并在页面上获得最深的内容:
var deepest = $('*').betterDeepest();
回答by casablanca
With a single path:
使用单一路径:
var elem = $('#table0'),
next;
while ((next = elem.children(':first')).length > 0)
elem = next;
// elem now points to the deepest child of table0
If I get time, I'll update my answer with the code for multiple paths.
如果我有时间,我会用多条路径的代码更新我的答案。
回答by user113716
Perhaps not the most efficient, but you could do this:
也许不是最有效的,但你可以这样做:
Example:http://jsfiddle.net/5N3Y7/
示例:http : //jsfiddle.net/5N3Y7/
var selector = 'body > *';
var $next = $(selector);
var $result = $next;
while( $next.length ) {
$result = $next;
selector += ' > *';
$next = $(selector);
}
$result.css('background','orange');
or this:
或这个:
Example:http://jsfiddle.net/5N3Y7/2/
示例:http : //jsfiddle.net/5N3Y7/2/
(The results in the example appear to be at different levels, but this is because the browser is inserting the missing <tbody>.)
(示例中的结果似乎处于不同级别,但这是因为浏览器正在插入缺少的<tbody>.)
var $next = $('body');
while ($next.length) {
$result = $next;
$next = $result.children();
}
$result.css('background', 'orange');
回答by rob
It's not jquery specific, but this recursive solution can be tweaked to do whatever you want.
它不是特定于 jquery 的,但是可以调整此递归解决方案以执行任何您想要的操作。
function findDeepest (elem) {
var result = {maxDepth: 0, deepestElem: null}
descend(elem, 0, result);
if (result.maxDepth > 0)
alert (result.deepestElem.tagName + " " + result.maxDepth);
}
function descend(elem, depth, result) {
switch (elem.nodeType) {
case 1: // ELEMENT_NODE
if (depth > result.maxDepth) {
result.maxDepth = depth;
result.deepestElem = elem;
}
for (var i=0; i<elem.childNodes.length; i++)
descend(elem.childNodes[i], depth + 1, result);
break;
case 3: // TEXT_NODE
case 4: // CDATA_SECTION_NODE
case 5: // ENTITY_REFERENCE_NODE
case 8: // COMMENT_NODE
// handle these cases as needed
break;
}
}
回答by Argimko
I think, this is shortest sample for you:
我认为,这对您来说是最短的示例:
$('#cell0 :last').text('new information')
It's really change innermost element, and save tags structure
它真的改变了最里面的元素,并保存了标签结构
回答by aercolino
Very late to the party, but here's my generic solution.
聚会很晚,但这是我的通用解决方案。
var elements$ = $(':contains("your text")');
var result = elements$.filter((index, element) =>
index === elements$.length ||
! $.contains(element, elements$.get(index+1))
);
It's very fast and simple, because jQuery already does all the job for us.
它非常快速和简单,因为 jQuery 已经为我们完成了所有工作。
Notice that elements$is an ordered list of containers, where many contain the next one. Thus the innermost elements are the last element plus all the elements that don't contain the next one.
请注意,这elements$是一个有序的容器列表,其中许多包含下一个。因此,最里面的元素是最后一个元素加上所有不包含下一个元素的元素。
回答by lumio
This question has a simple and good answer when for jQuery. However, I was looking for an elegant solution without it. Since :hasis not supported in any browser yet, I came up with this one here.
对于 jQuery,这个问题有一个简单而好的答案。但是,我一直在寻找没有它的优雅解决方案。由于:has尚不支持任何浏览器,我在这里想出了这个。
Array.from( document.querySelectorAll( 'body *' ) )
.filter( e => !e.children.length );
回答by Brendan
The first thing I would do is run a depth first search (DFS)and keep track of what level I was at for each node in the DOM.
我要做的第一件事是运行深度优先搜索 (DFS)并跟踪我在 DOM 中的每个节点所处的级别。
In order to save having to perform a full DFS every time you want to change something (assuming you'd like to do it multiple times), you could tag each DOM node with its level in the tree as the search is performed. (Then again, you could maybe do this level tagging during the generation of the table?) Once the search is completed and you've determined the deepest node, keep a reference to that node.
为了避免每次想要更改某些内容时都必须执行完整的 DFS(假设您想多次更改),您可以在执行搜索时用树中的级别标记每个 DOM 节点。(再说一次,您可以在生成表的过程中进行此级别标记吗?)一旦搜索完成并且您确定了最深的节点,请保留对该节点的引用。
From that point, you should be able to quickly update what node is at the deepest level at any given time.
从那时起,您应该能够在任何给定时间快速更新最深级别的节点。

