检查元素是否在 jQuery 中的另一个元素之前或之后

发布于 2024-12-02 00:24:50 字数 490 浏览 0 评论 0原文

假设我有这个标记

<h3 id="first">First</h3>
<p>Hi</p>
<p>Hello</p>
<h3 id="second">Second</h3>
<p>Bye</p>
<p>Goodbye</p>

,如何以编程方式检查某个元素(例如其中一个 p)是否位于第一个 h3 之后和第二个 h3 之前,用 jQuery?

我正在尝试做这样的事情:

$(p).each(function(){
   if($(this).isAfter("#first") && $(this).isBefore("#second")) {
     // do stuff
   }
});

Let us suppose I have this markup

<h3 id="first">First</h3>
<p>Hi</p>
<p>Hello</p>
<h3 id="second">Second</h3>
<p>Bye</p>
<p>Goodbye</p>

How can I programmatically check if an element, such as one of the ps, is after first h3 and before the second h3, with jQuery?

I am trying to do something like this:

$(p).each(function(){
   if($(this).isAfter("#first") && $(this).isBefore("#second")) {
     // do stuff
   }
});

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

野味少女 2024-12-09 00:24:50

如果 sel 是一个真正的选择器,Rocket 的解决方案可以正常工作,但如果您传递 jquery 对象,它就不起作用。

如果您想要一个同时适用于选择器和 jquery 对象的插件,只需使用我稍微修改过的版本即可:

(function($) {
    $.fn.isAfter = function(sel){
        return this.prevAll().filter(sel).length !== 0;
    };

    $.fn.isBefore= function(sel){
        return this.nextAll().filter(sel).length !== 0;
    };
})(jQuery);

感谢 Rocket 的原始解决方案。

Rocket's solution works fine if sel is a real selector, if you pass a jquery object though, it won't work.

If you want a plugin that works with both selectors and jquery objects, just use my slightly modified version instead:

(function($) {
    $.fn.isAfter = function(sel){
        return this.prevAll().filter(sel).length !== 0;
    };

    $.fn.isBefore= function(sel){
        return this.nextAll().filter(sel).length !== 0;
    };
})(jQuery);

Kudos to Rocket for the original solution.

琉璃繁缕 2024-12-09 00:24:50

要查看一个元素是否在另一个元素之后,可以使用 prev()prevAll() 获取前一个元素,然后查看如果匹配的话。

要查看一个元素是否在另一个元素之前,您可以使用 next()nextAll() 获取下一个元素,并且看看是否匹配。

$.fn.isAfter = function(sel){
  return this.prevAll(sel).length !== 0;
}
$.fn.isBefore= function(sel){
  return this.nextAll(sel).length !== 0;
}

演示:http://jsfiddle.net/bk4k7/

To see if an element is after another, you can use prev() or prevAll() to get the previous element(s), and see if it matches.

And to see if an element is before another, you can use next() or nextAll() to get the next element(s), and see if it matches.

$.fn.isAfter = function(sel){
  return this.prevAll(sel).length !== 0;
}
$.fn.isBefore= function(sel){
  return this.nextAll(sel).length !== 0;
}

DEMO: http://jsfiddle.net/bk4k7/

鹊巢 2024-12-09 00:24:50

您可以使用 index() 函数:

$('p').each(function(){
   var index = $(this).index();
   if(index > $("#first").index() && index < $("#second").index()) {
     // do stuff
   }
});

You can use the index() function:

$('p').each(function(){
   var index = $(this).index();
   if(index > $("#first").index() && index < $("#second").index()) {
     // do stuff
   }
});
初相遇 2024-12-09 00:24:50

这是一个 小提琴

$('p').each(function() {
    previousH3 = $(this).prevAll('h3');
    nextH3 = $(this).nextAll('h3');

    if (previousH3.length > 0 && nextH3.length > 0) {
        $(this).css('color', 'red')
    }

});

Here is a fiddle

$('p').each(function() {
    previousH3 = $(this).prevAll('h3');
    nextH3 = $(this).nextAll('h3');

    if (previousH3.length > 0 && nextH3.length > 0) {
        $(this).css('color', 'red')
    }

});
猫七 2024-12-09 00:24:50

我实现了一个通用的 isAfter 函数,它考虑了深度和 DOM 树,并且可以正确确定 a 是否在 b 之后,即使它们在 2 中不同的子树:

<div>
  <div>
    <p class="first">I come first</p>
  </div>
</div>

<div>
  <div>
    <p class="second">I come second</p>
  </div>
</div>

您可以在 我的 GitHub 存储库 中找到它。感谢您对代码的反馈

I implemented a general isAfter function, which considers the depth and DOM tree and can correctly determine if a is after b even if they are in 2 different subtrees:

<div>
  <div>
    <p class="first">I come first</p>
  </div>
</div>

<div>
  <div>
    <p class="second">I come second</p>
  </div>
</div>

you can find it in my GitHub Repository. Would appreciate your feedback on the code

听不够的曲调 2024-12-09 00:24:50

答案:

$.fn.isAfter = function(sel){
    return this.prevAll(sel).length !== 0;
}
$.fn.isBefore= function(sel){
    return this.nextAll(sel).length !== 0;
}

无论选择器 (sel) 如何,都会选择所有先前的元素或下一个元素,因此我进行了以下修改,根据类选择元素:

$.fn.isAfter = function(sel){
    sel = "." + sel.attr("class").replace(/ /g, ".");

    return this.prevAll(sel).length !== 0;
}
$.fn.isBefore= function(sel){
    sel = "." + sel.attr("class").replace(/ /g, ".");

    return this.nextAll(sel).length !== 0;
}

The answer:

$.fn.isAfter = function(sel){
    return this.prevAll(sel).length !== 0;
}
$.fn.isBefore= function(sel){
    return this.nextAll(sel).length !== 0;
}

Was selecting all previous elements or next elements regardless of the selector (sel) so I made the following modifications that select elements based on class:

$.fn.isAfter = function(sel){
    sel = "." + sel.attr("class").replace(/ /g, ".");

    return this.prevAll(sel).length !== 0;
}
$.fn.isBefore= function(sel){
    sel = "." + sel.attr("class").replace(/ /g, ".");

    return this.nextAll(sel).length !== 0;
}
梦途 2024-12-09 00:24:50

此版本适用于任何深度,比较两个元素是否在彼此之前、相等或之后。分别返回 -1、0 和 1。

它的工作原理是获取传递给比较函数的元素的所有索引偏移量。

然后它比较两个偏移量数组,并在发现差异时停止迭代。

var topElement = $("span").eq(0);
var bottomElement = $("span").eq(2);

var res = compare(topElement, bottomElement);

console.log("The compare result is: " + res)



function getOffsets(el)
{
  var res = new Array();
  
  while(el.length > 0)
  {
    res.push(el.index());
    el = el.parent();
    }
  
  return res.reverse();
}

function compare(a, b)
{  
  var offA = getOffsets(a);
  var offB = getOffsets(b);
  
  
  for(let i = 0; i < offA.length + 1; i++)
  {
        let delta = (offA[i] || -1) - (offB[i] || -1);
    
    if(delta < 0)
      return -1;
    else if(delta > 0)
      return 1;
  }
  
  return 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div>
    <span>1</span>
</div>
<div>
    <div>
        <span>2</span>
    </div>
</div>
<div>
    <div>
        <div>
            <span>3</span>
        </div>
    </div>
</div>

This version works at any depth comparing if two elements are before, equal, or after each other. Returning -1, 0, and 1 respectively.

How it works is that it gets all the index offsets of the elements passed into the compare function.

Then it compares the two array of offsets and stops iterating when it finds a discrepancy.

var topElement = $("span").eq(0);
var bottomElement = $("span").eq(2);

var res = compare(topElement, bottomElement);

console.log("The compare result is: " + res)



function getOffsets(el)
{
  var res = new Array();
  
  while(el.length > 0)
  {
    res.push(el.index());
    el = el.parent();
    }
  
  return res.reverse();
}

function compare(a, b)
{  
  var offA = getOffsets(a);
  var offB = getOffsets(b);
  
  
  for(let i = 0; i < offA.length + 1; i++)
  {
        let delta = (offA[i] || -1) - (offB[i] || -1);
    
    if(delta < 0)
      return -1;
    else if(delta > 0)
      return 1;
  }
  
  return 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div>
    <span>1</span>
</div>
<div>
    <div>
        <span>2</span>
    </div>
</div>
<div>
    <div>
        <div>
            <span>3</span>
        </div>
    </div>
</div>

凉月流沐 2024-12-09 00:24:50

此单行检查适用

于本示例中使用的问题中的每种情况 ID:

document.getElementById("first") === document.querySelectorAll("#second, #first")[0]

querySelectorAll 方法中的 ID 顺序不相关,只需要使用在这种情况下选择两个元素的选择器#第二,#第一

如果您需要多次使用此功能,则可以使用此函数:

function isBeforeElement( first_id, second_id ) {
    return document.querySelectorAll('#' + first_id + ', #' + second_id)[0] === document.getElementById(first_id);
}

即使在特殊情况下,此函数也不会出现错误:

  1. 如果未找到两个元素,则将返回false
  2. 如果第二个元素未找到,它将返回true
  3. 如果第一个元素未找到它将返回false

This one-liner check will work in every case

IDs from your question used for this example:

document.getElementById("first") === document.querySelectorAll("#second, #first")[0]

Order of IDs in querySelectorAll method is not relevant it is only necessary to use selector that will select both elements in this case #second, #first.

If you need to use this multiple times you can use this function:

function isBeforeElement( first_id, second_id ) {
    return document.querySelectorAll('#' + first_id + ', #' + second_id)[0] === document.getElementById(first_id);
}

This function will work without errors even in exceptional cases:

  1. If both elements are not found it will return false
  2. If second element is not found it will return true
  3. If first element is not found it will return false
阳光①夏 2024-12-09 00:24:50

记住 Rocket 的答案,我更喜欢使用 .index() 方法,如下所示:

$.fn.isAfter = function(sel){
    return $(this).index() > $(sel).index();
};
$.fn.isBefore= function(sel){
    return $(this).index() < $(sel).index();
};

它似乎更适合阅读/理解,并且在行选择中完美工作。

Keeping in mind Rocket's answer I prefer to use .index() approach like following:

$.fn.isAfter = function(sel){
    return $(this).index() > $(sel).index();
};
$.fn.isBefore= function(sel){
    return $(this).index() < $(sel).index();
};

It seems more clear for reading/understanding and works perfectly in rows selection.

爱的十字路口 2024-12-09 00:24:50

如果所讨论的元素是兄弟元素(它们在原始问题中),则前面的答案可以正常工作,但更通用的解决方案将考虑以下场景:

<div id="top">    
    <div>
        <div>
           <h3 id="first">First</h3>
           <p>Hi</p>
           <p>Hello</p>
        </div>
    </div>
    <div>
        <h3 id="second">Second</h3>
        <p>Bye</p>
        <p>Goodbye</p>
    </div>
</div>

更通用的解决方案是:

$.extend($.fn, {
    isBefore: function(sel, context) {
        // Get all element within the context.
        var all = $(context || document).find("*");
        return all.index(this[0]) < all.index($(sel));
    },

    isAfter: function(sel, context) {
        return !this.isBefore(sel, context);
    }
});

其中“上下文”是一个可选参数,仅限制jQuery 的搜索区域可提高性能。我没有执行任何测试,但“上下文”可能是不必要的,因为 $("*") 似乎执行速度很快。另请注意,如果任一元素不在上下文中,则 index() 将返回 -1。

$("#first").isBefore("#second");  
// Gives the same result as
$("#first").isBefore("#second", "#top");

当然,这一切都假设“之前”和“之后”是指它们在文档模型中的顺序。如果您担心它们在显示上的相对位置,您可能需要检查元素相对于文档的显示坐标,因为“相对”、“固定”和“绝对”CSS 位置使一切成为可能。

The previous answers work fine IF the elements in question are siblings (which they are in the original question) but a more general solution would consider the following scenario:

<div id="top">    
    <div>
        <div>
           <h3 id="first">First</h3>
           <p>Hi</p>
           <p>Hello</p>
        </div>
    </div>
    <div>
        <h3 id="second">Second</h3>
        <p>Bye</p>
        <p>Goodbye</p>
    </div>
</div>

A more general solution would be:

$.extend($.fn, {
    isBefore: function(sel, context) {
        // Get all element within the context.
        var all = $(context || document).find("*");
        return all.index(this[0]) < all.index($(sel));
    },

    isAfter: function(sel, context) {
        return !this.isBefore(sel, context);
    }
});

Where "context" is an optional parameter that merely limits the search area for jQuery to improve performance. I haven't performed any tests but "context" is probably unnecessary since $("*") seems to execute qualitatively fast. Also note that index() will return -1 is either element is not within the context.

$("#first").isBefore("#second");  
// Gives the same result as
$("#first").isBefore("#second", "#top");

Of course this all assumes that by "before" and "after" you mean their order in the document model. If you are concerned about their relative positions on the display you would want to examine the elements display coordinates relative to the document as "relative", "fixed" and "absolute" CSS positions make anything possible.

书间行客 2024-12-09 00:24:50

仅当元素处于同一级别时,接受的答案才有效。如果您想要定位第一个元素(无论级别如何),解决此问题的一种方法是:

  1. 为具有相同值的每个元素设置一个临时属性
  2. 使用 jquery 选择器来定位具有该属性值的第一个元素

The accepted answer only works if the elements are at the same level. One approach to solve it if you want to locate which element is first regardless of the level is:

  1. Set a temporary attribute to each element with the same value
  2. Use a jquery selector to locate the first element with that attribute value
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文