jQuery nextUntil()与comment元素一起工作很奇怪

时间:2017-05-18 17:53:48

标签: javascript jquery nextuntil

我需要帮助。我对jQuery' nextUntil()方法有一些奇怪的问题。它没有像我期待的那样工作......

我的HTML中有两个注释标记,用于分隔我感兴趣的元素以及我想要进入jQuery集合的元素。为此,我首先找到两个注释节点,并在第一个上应用nextUntil,将第二个作为参数提供。但是nextUntil会返回所有后面第一条评论的孩子,似乎忽略了我传递给它的论点。

如何防止这种情况发生,并且只有之间的孩子这两条评论呢?

这是我的代码:

HTML:

<ul>
  <li>1</li>
  <li>2</li>

  <!-- from -->

  <li>3</li>
  <li>4</li>

  <!--  to  -->

  <li>5</li>
  <li>6</li>
</ul>

JavaScript的:

  const fromSign = 'from'
  const toSign = 'to'

  // filter callback - return only comment
  // element with specific text
  function commentWith (elm, txt) {
    return elm.nodeType === 8 &&
           elm.nodeValue.trim() === txt
  }

  // Step - 1 find comment with "from"
  // text and save returned element
  const $start = $('ul').contents().filter(
    (idx, elm) => commentWith(elm, fromSign)
  )

  // Find comment with "to"
  // text and save returned element
  const $stop = $('ul').contents().filter(
    (idx, elm) => commentWith(elm, toSign)
  )

  console.info($start, $stop) // So far, so good

  // Step 2 - find all elements
  // between "from" and "to" comments
  let $inner = $start.nextUntil($stop)

  // Not works - inner contains elements
  // beyond "to" comment
  console.log($inner)

  // Step 2 again - find all elements
  // between "from" and "to" comments
  // with "redundant" prev/next
  $inner = $start.nextUntil($stop.prev().next())

  // OK, just li 3 and 4,
  // but why? What am I missing?
  console.log($inner)

PS:如果您使用<div class="from"><div class="end">或其他元素来选择开始和结束,nextAll()将按预期工作。但是,我想用注释标记选择....

我尝试使用prev / next&#34; hacks&#34;作为替代方案(参见上面的代码),但当评论标记之前和/或之后没有元素时,它们表现不佳。

1 个答案:

答案 0 :(得分:-1)

代码的第一个变体失败的原因是大多数jQuery方法只查看元素,而不是其他节点类型的节点。如jQuery documentation on contents中所述:

  

请注意,大多数jQuery操作都不支持文本节点和注释节点。少数人会在他们的API文档页面上有明确的说明。

在您的情况下,对nextUntil的调用只会逐步执行元素,甚至不会查看其他节点,因此它会&#34;错过&#34; $ stop 节点。

解决方法是使用index()。当开始标记之前没有元素和/或停止标记之后没有元素时,这也可以很好地工作。如果 是一个元素节点,那么非元素节点返回的索引将是 所拥有的索引。

&#13;
&#13;
const fromSign = 'from'
const toSign = 'to'

// filter callback - return only comment
// element with specific text
function commentWith (elm, txt) {
    return elm.nodeType === 8 &&
           elm.nodeValue.trim() === txt
}

// Step - 1 find comment with "from"
// text and save returned index
const startIndex = $('ul').contents().filter(
    (idx, elm) => commentWith(elm, fromSign)
).index();

// Find comment with "to"
// text and save returned index
const stopIndex = $('ul').contents().filter(
    (idx, elm) => commentWith(elm, toSign)
).index();

console.log('indexes:', startIndex, stopIndex);

// Step 2 - get all child elements
// between "from" and "to" comments
let $inner = $('ul').children().slice(startIndex, stopIndex);

// Now it works - inner contains the elements between the markings
console.log('selected first and last text:', $inner.first().text(), $inner.last().text());
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
    <li>1</li>
    <li>2</li>

    <!-- from -->

    <li>3</li>
    <li>4</li>

    <!--  to  -->

    <li>5</li>
    <li>6</li>
</ul>
&#13;
&#13;
&#13;