【问题标题】:Next element in *entire* document after certain element*整个*文档中某个元素之后的下一个元素
【发布时间】:2011-06-29 12:46:18
【问题描述】:

这是一个被问了很多次的问题的变体。给定任何元素,我希望能够在 entire 文档中找到它之后的任何其他元素。它可以是兄弟,但也可以是之后出现的任何其他元素。例如,给定以下标记,

<div>
    <p>Hello</p>
    <div>
        <p>Foo</p>
        <p class="bar">Bar</p>
        <p>rawr!</p>
    </div>
    <p>bop</p>
    <input/>
    <div>
        <p>Another</p>
        <div>
            <span>something</span>
            <p>deep!</p>
        </div>
    </div>
</div>
<p>last</p>

为了便于描述,假设我正在寻找的函数称为$.fn.nextInDocument。如果我打电话:

$('.bar').nextInDocument('p'); //  <p>rawr</p>
$('.bar').nextInDocument('p').nextInDocument('p'); //  <p>bop</p>

继续,它会得到&lt;p&gt;Another&lt;/p&gt;,然后是&lt;p&gt;deep!&lt;/p&gt;,最后是&lt;p&gt;last&lt;/p&gt;

这样的东西存在吗?我不在乎它是选择器还是函数。我只需要功能。

编辑更新了 DOM 结构,使其成为一个更具挑战性的问题,但更清楚我要寻找的内容。

【问题讨论】:

    标签: javascript jquery html dom


    【解决方案1】:

    这个怎么样?这是一个通用的解决方案,它使用 DOM 方法依次遍历节点并针对 jQuery 选择器测试每个节点。

    jsFiddle:http://jsfiddle.net/PsEdZ/3/

    (function($) {
        function nextNode(node, omitChildren) {
            var sibling, parentNode;
            if (!omitChildren && node.hasChildNodes()) {
                return node.firstChild;
            } else {
                sibling = node.nextSibling;
                if (sibling) {
                    return sibling;
                } else {
                    parentNode = node.parentNode;
                    return parentNode ? nextNode(parentNode, true) : null;
                }
            }
        }
    
        $.fn.nextInDocument = function(selector) {
            var node = this[0], $node;
            while ( (node = nextNode(node)) ) {
                $node = $(node);
                if ($node.is(selector)) {
                    return $node;
                }
            }
            return null;
        }
    })(jQuery);
    

    【讨论】:

    • 到目前为止,这一切都经受住了我的努力。我想知道它的性能如何,到目前为止我不打算在过大的页面上运行。非常感谢!
    • @Jeff:它可能会被优化:例如,我认为评估每个节点的选择器可能会导致性能问题。我建议只在造成瓶颈时才这样做。
    【解决方案2】:

    这应该可行。虽然不确定它是否有用......

    ;(function ($)
    {
        $.fn.nextInDocument = function (s)
        {
            var self = this,
                next;
            do
            {
                next = self.nextAll(s).first();
                self = self.parent();
            }
            while (self.length && !next.length);
    
            return next;
        };
    })(jQuery);
    

    演示:http://jsfiddle.net/mattball/HAFn8/

    【讨论】:

    • @Matt Ball 在当前元素之后进入子元素有一些问题,尽管我不确定他是否甚至在使用这样的功能:jsfiddle.net/niklasvh/HAFn8/3
    • 感谢您指出这一点。一个明显的缺陷,如果需要,它肯定会使事情变得更加复杂。需要更好的树遍历算法。
    • 我不太确定它是如何工作的,但它看起来很有希望。我把它放在小提琴中,没有办法匹配选择器。换句话说$('.bar').nextInDocument('p') == $('.bar').nextInDocument('div') == '&lt;p&gt;rawr!&lt;/p&gt;.
    • 我的要求确实需要再次向下遍历树,但不幸的是,这可能是
    • @Jeff 我不明白你说的 "$('.bar').nextInDocument('p') == $('.bar').nextInDocument('div') == '&lt;p&gt;rawr!&lt;/p&gt;" 是什么意思
    【解决方案3】:
    (function(jQuery) {
    jQuery.fn.extend({
        nextInDocument: function(a) {
            if (jQuery(this).next(a).length === 0) {
                //console.log($(this).parent().nextInDocument('p'));
                jQuery(this).parent().nextInDocument(a);
            }
            else
                return jQuery(this).next(a);
        }
    });
    })(jQuery);
    

    【讨论】:

    • 感谢布帕蒂。我不确定我是否遗漏了什么。我把它放在一个小提琴中,你的函数返回每个调用的原始元素,例如$('.bar').nextInDocument('div')==&lt;p&gt;rawr&lt;/p&gt;jsfiddle.net/jeffrod/nHeGU
    • 对此感到抱歉……已更正……检查……还有一个小错误。会改进...
    • 我从这里得到空值。它似乎仍然不起作用
    【解决方案4】:

    这是一个 POJS 版本:

    function nextInDocument(el, tagName) {
      var node, nodes = document.getElementsByTagName('*');
      var start = false;
      tagName = tagName.toLowerCase();
    
      for (var i=0, iLen=nodes.length; i<iLen; i++) {
        node = nodes[i];
        if (!start) {
          if (node == el) start = true;
        } else {
          if (node.tagName.toLowerCase() == tagName) {
            return node;
          }
        }
      }
    }
    

    【讨论】:

    • 普通旧 js 的好解决方案。谢谢。 jquery 可以使用更复杂的选择器,但这使得其他一些 sn-ps 对我的特定情况更具吸引力。
    • 小心这种方法,如果选择器过于复杂,您可能会发现性能问题。考虑改用类,以便更容易找到下一个元素。
    • 好点。如果性能成为问题,我会考虑。
    【解决方案5】:

    看看我的代码:

    HTML

    <div>
        <p>Hello</p>
        <div> 
            <p>Foo</p>
            <p>Fooooo</p>
            <p class="bar">Bar</p>
            <p>rawr!</p>
        </div>
        <p>bop</p>
        <input/>
        <div>
            <p>Another</p>
        </div>
    </div>
    <p>last</p>
    
    <a class="show" href="#">!!!</a>
    

    JS

    $(function() {
        i = 0;
        start = 0;
        $('p').each(function() {
            if ($(this).hasClass('bar')) {
                start = i;
            }
            i++;
        });
        $('a.show').click( function(){
            alert($('p').eq(start+4).text());
        });
    });
    

    http://jsfiddle.net/mV8pm/

    更改start+X,你会得到下一个'p'标签

    【讨论】:

    • 谢谢。这似乎与我在演示中给出的标记紧密耦合,但我需要一些可以“适用于任何元素”并抓住“它之后的任何元素”的东西。我认为这不会那么灵活
    • 我敢打赌它会 :) 在不同的 DOM 上试一试。您只需将此代码放入 JQ 函数即可。顺便说一句,开始元素的标签(按类选择)和您要查找的标签应该是相同的(例如'p')。
    猜你喜欢
    • 2013-05-29
    • 2020-05-10
    • 2019-11-17
    • 2021-07-02
    • 2015-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多