如何选择最里面的元素?

时间:2010-11-15 21:21:52

标签: javascript jquery html

在jQuery中,我如何尽可能地下降到HTML树中?

为简单起见,我只有一条路向下。

(相关但奖励:如何找到具有多个向下路径的最深元素?)

<html>  
  <table id="table0">  
    <tr>  
      <td id="cell0">  
        <div class"simple">  I want to change this information </div>  
      </td>
    </tr>  
  </table>  
</html>

我想更改名为 cell0 的单元格的最里面的HTML,但我不一定知道里面所有类的名称。是否有可能在不知道这些名称的情况下选择这一点?

非常感谢!

10 个答案:

答案 0 :(得分:24)

对于单路径,只需找到没有子节点的元素:

$('body *:not(:has("*"))');

或者,在您更具体的案例中$('#cell0 *:not(:has("*"))');

对于多个路径 - 如果有多个同样嵌套的节点会怎么样?此解决方案将为您提供所有具有最多祖先数的节点的数组。

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); 
    }
});

同样,在你的情况下,你可能想要获得表格单元格中最深的元素,所以你又回到了单行:

$('#table0 td *:not(:has("*"))');

- 这将返回一个jQuery对象,其中包含表中每个单元格的所有最内层子节点。

答案 1 :(得分:4)

我是通过一个递归函数来完成的:

// 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;
}

答案 2 :(得分:1)

好吧,从你不知道这个“最深”节点在哪里的基础开始,你可以这样做:

$.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;
  });
});

然后

var $deepest = $('body').deepest();

会(除了我的代码中的12个错误)将是最深层元素集的jQuery对象。

编辑 - 我的十几个错误之一就是没有考虑起始节点的深度 - 这是一个弄清楚的伎俩。可能更好地重构它,以便它找到最初选择列表中最深的列表:

$.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; });
});

并在您要执行的页面上获得最深处:

var deepest = $('*').betterDeepest();

答案 3 :(得分:1)

使用单一路径:

var elem = $('#table0'),
    next;
while ((next = elem.children(':first')).length > 0)
  elem = next;
// elem now points to the deepest child of table0

如果我有时间,我会用多条路径的代码更新我的答案。

答案 4 :(得分:0)

也许不是最有效的,但你可以这样做:

示例: 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');

或者这个:

示例: http://jsfiddle.net/5N3Y7/2/

(示例中的结果似乎处于不同级别,但这是因为浏览器正在插入缺少的<tbody>。)

var $next = $('body');

while ($next.length) {
    $result = $next;
    $next = $result.children();
}

$result.css('background', 'orange');

答案 5 :(得分:0)

这不是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;
    }
}

答案 6 :(得分:0)

我要做的第一件事是运行depth first search (DFS)并跟踪DOM中每个节点的等级。

为了节省每次想要更改某些内容时必须执行完整的DFS(假设您想要多次执行),您可以在执行搜索时使用树中的级别标记每个DOM节点。 (那么,您可以在生成表格时进行此级别标记吗?)一旦搜索完成并确定了最深的节点,请保留对该节点的引用。

从那时起,您应该能够在任何给定时间快速更新最深层次的节点。

答案 7 :(得分:0)

我认为,这是最简短的样本:

$('#cell0 :last').text('new information')

它确实改变了最内层的元素,并保存了标签结构

答案 8 :(得分:0)

聚会很晚,但这是我的通用解决方案。

var elements$ = $(':contains("your text")');
var result = elements$.filter((index, element) => 
        index === elements$.length || 
        ! $.contains(element, elements$.get(index+1))
    );

它非常快速和简单,因为jQuery已经为我们完成了所有工作。

请注意,elements$是一个有序的容器列表,其中许多包含下一个容器。因此,最里面的元素是最后一个元素加上所有不包含下一个元素的元素。

答案 9 :(得分:0)

当使用jQuery时,此问题有一个简单而好的答案。但是,我一直在寻找一个没有它的优雅解决方案。由于目前尚无任何浏览器支持:has,因此我在这里提出了这个建议。

Array.from( document.querySelectorAll( 'body *' ) )
  .filter( e => !e.children.length );