Выбор набора абзацев с помощью jQuery

У меня есть HTML файл, содержащий наборы абзацев, например:

<p>Page 1</p>
<p>Paragraph 1</p>
<p>Paragraph 2</p>

<p>Page 2</p>
<p>First line.</p>
<p>Some text here.</p>
<p>Some other text here.</p>

<p>Page 3</p>
<p>Paragraph 1</p>
<p>Paragraph 2</p>

Мне нужно выбрать все абзацы на странице. Содержимое первого абзаца на странице n всегда "Страница n", но количество абзацев на странице является переменной, равно как и содержание абзацев, следующих за номером страницы.

Как выбрать абзацы между страницами n и Page n + 1?

До сих пор я мог только выяснить, как выбрать первый абзац на странице, используя jQuery:

var n = 2;
$("p:contains(Page " + n + ")").next("p").css('background-color', 'red');

Спасибо заранее.

Ответ 1

Если вы застряли в этой структуре, вы ищете nextUntil, который добавляет следующие элементы до (и не включая ) элемент, соответствующий селектору, который вы его передаете:

var n = 2;
$("p:contains(Page " + n + ")").nextUntil("p:contains(Page " + (n + 1) + ")").css('background-color', 'red');

(Пример в прямом примере ниже.)

Это выбирает только абзацы после абзаца "Страница n", а не сам "Page n". Если вы также хотите включить абзац "Страница n", используйте addBack (ранее andSelf, но andSelf устарел в пользу addBack в v1.8), например:

var n = 2;
$("p:contains(Page " + n + ")")
    .nextUntil("p:contains(Page " + (n + 1) + ")")
    .addBack()
    .css('background-color', 'red');

Но если вы можете изменить структуру, я бы, вероятно, поместил содержимое каждой страницы в элемент оболочки, например section

<section data-page="1">
    <h1>Page 1</h1>
    <p>Paragraph 1</p>
    <p>Paragraph 2</p>
</section>
<section data-page="2">
    <h1>Page 2</h1>
    <p>First line.</p>
    <p>Some text here.</p>
    <p>Some other text here.</p>
</section>
<section data-page="3">
    <h1>Page 3</h1>
    <p>Paragraph 1</p>
    <p>Paragraph 2</p>
</section>

Обратите внимание, что я также включил атрибут data-*, идентифицирующий страницу (также изменил абзацы, содержащие номера страниц, на h1; спецификация рекомендует включать элемент h1 - h6 для идентификации раздела). Тогда это будет просто:

$("section[data-page=" + n + "] > p").css(/*...*/);

Пример в реальном времени с использованием текущей структуры (без addBack):

var colors = {
  1: "red",
  2: "green",
  3: "blue"
};
var n;
for (n = 1; n <= 3; ++n) {
  $("p:contains(Page " + n + ")").nextUntil("p:contains(Page " + (n + 1) + ")").css('background-color', colors[n]);
}
<p>Page 1</p>
<p>Paragraph 1</p>
<p>Paragraph 2</p>

<p>Page 2</p>
<p>First line.</p>
<p>Some text here.</p>
<p>Some other text here.</p>

<p>Page 3</p>
<p>Paragraph 1</p>
<p>Paragraph 2</p>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

Ответ 2

Если вы можете написать "Страница 1" --- "Страница n", то, возможно, параграфы должны иметь класс? Могу ли я предположить, что они динамически добавлены?

Так же:

<p class="p1">Page 1</p>
<p class="belongs_p1">Paragraph 1</p>
<p class="belongs_p1">Paragraph 2</p>

<p class="p2">Page 2</p>
<p class="belongs_p2">First line.</p>
<p class="belongs_p2">Some text here.</p>
<p class="belongs_p2">Some other text here.</p>

<p class="p3">Page 3</p>
<p class="belongs_p3">Paragraph 1</p>
<p class="belongs_p3">Paragraph 2</p>

Таким образом вы можете выбрать абзац и все абзацы, принадлежащие ему, без необходимости вызывать содержимое абзаца.

Ответ 3

Я предлагаю вам добавить id для каждого абзаца.

<p id="one">Page 1</p>
<p>Paragraph 1</p>
<p>Paragraph 2</p>

<p id="two">Page 2</p>
<p>First line.</p>
<p>Some text here.</p>
<p>Some other text here.</p>

<p id="three">Page 3</p>
<p>Paragraph 1</p>
<p>Paragraph 2</p>

Эта функция jquery выбирает элементы между двумя тегами по id.

(function ($) {
    $.fn.between = function (elm0, elm1) {
        var index0 = $(this).index(elm0);
        var index1 = $(this).index(elm1);

        if (index0 <= index1)
            return this.slice(index0, index1 + 1);
        else
            return this.slice(index1, index0 + 1);
    }
})(jQuery);

Вы можете использовать его таким образом

$('body').between($('#one'), $('#two')).each(function () {
    // Do what you want.
});