获取李有一个类而没有其他类的索引

Get index of li have a class and do not have another class

本文关键字:其他 索引 有一个 获取      更新时间:2023-09-26

我有下面的代码来查找具有类active而没有hidden类的li的索引。为了找到值,我们不想计算hidden类。

var index = $('li').not('.hidden').find('.active').index();
alert(index)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
  <li class="hidden">.....</li>
  <li>....</li>
  <li class="hidden">....</li>
  <li class="active">....</li>
  <li>....</li>
  <li class="hidden">....</li>
  <li>....</li>
 </ul>

这里我得到了结果-1,但我预期的结果是1。有可能找到这个吗?

您可以使用.filter(),它在同一级别中搜索,即匹配元素的子集,其中.find()在子元素中查找

var index = $('li').not('.hidden').filter('.active').index();

,可以作为进行改进

var index = $('li.active:not(.hidden)').index();

如果需要排除.hidden,则需要从无序列表中删除它们,然后可以使用.index()

var index = $('ul').clone().find('li.hidden').remove().end().find('li.active').index();

var index = $('ul').clone().find('.hidden').remove().end().find('li.active').index();
console.log(index)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
  <li class="hidden">hidden</li>
  <li>....</li>
  <li class="hidden">hidden</li>
  <li class="active">active</li>
  <li>....</li>
  <li class="hidden">hidden</li>
  <li>....</li>
</ul>

虽然在撰写本文时您已经接受了另一个答案,但我想我应该提供一种替代方法,使用纯JavaScript来做同样的事情(尽管有进一步、简单的定制选项):

// using a named function allows you to call that function
// repeatedly in response to interaction or other events:
function findIndexOf(opts) {
  // setting the 'default' settings of the function,
  // these defaults can be overridden by the user:
  // 'needle':          String, the class-name of the element(s)
  //                    whose index/indices you wish to find.
  // 'haystack':        String, the CSS selector for those elements
  //                    from which you expect to find the 'needle(s).'
  // 'disregard':       String, the class-name of those elements in
  //                    the haystack you wish to disregard from the
  //                    index 'count.'
  // 'firstIndexOnly' : Boolean, true -  return only the index of the
  //                                     first needle found;
  //                             false - return the indices of all
  //                                     found needles.
  let settings = {
    'needle': 'active',
    'haystack': 'ul li',
    'disregard': 'hidden',
    'firstIndexOnly': true
  };

  // Using Array.prototype.forEach() to iterate over the
  // array of keys returned from Object.keys, of either
  // the 'opts' Object (supplied by the user to override
  // the default settings), or an empty Object to prevent
  // errors being thrown if the opts Object doesn't exist:
  Object.keys(opts || {}).forEach(function(key) {
    // 'key' is supplied the anonymous function,
    // and refers to the current key of the array
    // over which we're iterating.
    // here we update the settings[key] with the value of
    // opts[key]:
    settings[key] = opts[key];
  });
  // Using Array.from() to convert the NodeList returned by
  // document.querySelectorAll( settings.haystack ) into an
  // Array, in order to employ Array methods on that collection:
  let lis = Array.from(document.querySelectorAll(settings.haystack)),
    // here we use Array.prototype.filter(), with an Arrow
    // function syntax, to retain only those elements
    // whose classList does not contain the class identified
    // by the settings.disregard option, thereby removing the
    // options to be disregarded from the collection:
    notDisregarded = lis.filter(el => el.classList.contains(settings.disregard) === false),
    // iterating over the NotHiddenLis Array with
    // Array.prototype.map(), to obtain the indices of
    // those elements matching the class-name supplied
    // by the settings.needle option:
    indices = notDisregarded.map(function(el, index) {
      // Again, the arguments here are supplied by the
      // anonymous function though the names are chosen
      // by the user, the first argument (here 'el')
      // is the array element of the Array over which
      // we're iterating; 'index' (the second argument)
      // is the index of that current array element.
      // element.classList.contains() returns a Boolean
      // true, if the class-name supplied is found within
      // the classList of the element; or false if it is
      // not found.
      if (el.classList.contains(settings.needle)) {
        // if the element has the supplied class-name
        // (the string held in the settings.needle variable)
        // el.classList.contains() evaluates to true, and then
        // we return the associated index:
        return index;
      }
    // because the above approach returns undefined (when the
    // element.classList.contains() returns false) we here use
    // Array.prototype.filter(), with an Arrow function, to
    // retain only those array-elements that hold a value:
    }).filter(value => value);
  // to ensure we behave similarly to Array.prototype.indexOf(),
  // and String.prototype.indexOf(), we check the length of
  // the array of found indices and, if no elements were found,
  // and therefore no indices were retained, we push the value of
  // -1 into the array:
  if (indices.length === 0) {
    indices.push(-1);
  }
  // if the the settings.firstIndexOnly option is set to true,
  // we return an array consisting of only the first array-element
  // from the indices array, otherwise we return the whole array
  // (whether that array contains only one value or multiple).
  // We wrap the first array-value within an array in order to
  // provide consistency in the returned values, so that the
  // function always returns an Array:
  return settings.firstIndexOnly === true ? [indices[0]] : indices;
}
// Almost entirely irrelevant, this is just to tidy the
// console/snippet output:
let found = findIndexOf(),
    prepend = found.length === 1 ? 'Index: ' : 'Indices: ';
// showing the output of the function in the snippet.log
// (with thanks to T.J. Crowder):
snippet.log(prepend + JSON.stringify(found) );

function findIndexOf(opts) {
  let settings = {
    'needle': 'active',
    'haystack': 'ul li',
    'disregard': 'hidden',
    'firstIndexOnly': true
  };
  Object.keys(opts || {}).forEach(function(key) {
    settings[key] = opts[key];
  });
  let lis = Array.from(document.querySelectorAll(settings.haystack)),
    notDisregarded = lis.filter(el => el.classList.contains(settings.disregard) === false),
    indices = notDisregarded.map(function(el, index) {
      if (el.classList.contains(settings.needle)) {
        return index;
      }
    }).filter(value => value);
  if (indices.length === 0) {
    indices.push(-1);
  }
  return settings.firstIndexOnly === true ? [indices[0]] : indices;
}
let found = findIndexOf(),
    prepend = found.length === 1 ? 'Index: ' : 'Indices: ';
snippet.log(prepend + JSON.stringify(found) );
li {
  height: 2em;
  line-height: 2em;
  border: 1px solid currentcolor;
  margin: 0 0 0.5em 0;
  list-style-type: none;
}
.hidden {
  color: #f90;
  width: 80%;
  opacity: 0.6;
}
.active {
  color: limegreen;
  width: 50%;
}
li::before {
  content: attr(class);
  display: inline-block;
  text-indent: 1em;
}
<!-- Provides the `snippet` object, see https://meta.stackexchange.com/a/242144/134069 -->
<script src="https://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
<ul>
  <li class="hidden">.....</li>
  <li>....</li>
  <li class="active">....</li>
  <li class="hidden">....</li>
  <li>....</li>
  <li class="hidden">....</li>
  <li class="active">....</li>
</ul>

JS Fiddle演示。

作为一种潜在但不太可能相关的替代方案(完全取决于您的用例),您可以单独使用CSS进行类似的操作,尽管值得明确指出的是,这种方法只能对元素进行样式设置,尽管可以使用CSS生成的内容和伪元素添加内容(同样,我不认为这是你想要的,但我不确定,它可能在未来对其他人有用):

li {
  height: 2em;
  line-height: 2em;
  border: 1px solid currentcolor;
  margin: 0 0 0.5em 0;
  list-style-type: none;
}
.hidden {
  color: #f90;
  width: 80%;
  opacity: 0.6;
}
.active {
  color: limegreen;
  width: 50%;
}
li::before {
  content: attr(class);
  display: inline-block;
  text-indent: 1em;
}
/* Selecting those <li> elements that do
   not have the 'hidden' class-name: */
li:not(.hidden) {
  /* defining a counter to increment
     each time an matching element is found: */
  counter-increment: liActive;
}
/* Selecting those <li> elements with the class
   of 'active' that do not have the class of
   'hidden', and defining a pseudo-element for
   those elements: */
li:not(.hidden).active::after {
  /* Setting up some content to be shown, in this
     case the string of 'Index: ' concatenated
     with the output of the CSS counter function: */
  content: 'Index: ' counter(liActive);
  color: red;
  float: right;
}
<ul>
  <li class="hidden">.....</li>
  <li>....</li>
  <li class="active">....</li>
  <li class="hidden">....</li>
  <li>....</li>
  <li class="hidden">....</li>
  <li class="active">....</li>
</ul>

JS Fiddle演示。

参考文献:

  • CSS:
    • counter-increment
    • CSS伪元素
    • 否定(:not())伪类
    • "使用CSS计数器。"
  • JavaScript:
    • CCD_ 10
    • CCD_ 11
    • Array.prototype.forEach()
    • Array.prototype.map()
    • Array.prototype.push()
    • 箭头函数语法
    • document.querySelector()
    • CCD_ 16
    • Element.classList API
    • CCD_ 18
    • let语句
    • CCD_ 20

工具:

  • snippet.js,由T.J Crowder创建,位于:https://meta.stackexchange.com/a/242144/130770

不用ul

var index = $('ul').not('.hidden').find('.active').index();
alert(index)