简体   繁体   中英

Cycling through a jQuery object with elements grouped together

I have a set of list items that contain nested lists, sort of like this:

<ul class="searchselectors">
  <li class="group">Group name 1
    <ul>
      <li class="item selected">List item 1.1</li>
      <li class="item">List item 1.2</li>
      <li class="item">List item 1.3</li>
    </ul>
  </li>
  <li class="group">Group name 2
    <ul>
      <li class="item">List item 2.1</li>
      <li class="item">List item 2.2</li>
      <li class="item">List item 2.3</li>
    </ul>
  </li>
  <li class="group">Group name 3
    <ul>
      <li class="item">List item 3.1</li>
    </ul>
  </li>
</ul>

I want to cycle through all of the .item elements using up/down arrow keys (which I already have set up by using on('keydown') and catching key codes 38 and 40 ) and set .selected on the next item before or after the currently selected item, wrapping around to the top/bottom as necessary.

Using $().next() and $().prev() will not work, since it will only work on siblings , and not on a jQuery object such as $('.searchselectors .item') .\\

I was working on the same problem but in my project I'm using KnockoutJS . In fact, the original logic was written with pure jQuery and I refactored it with Knockout. Here's a solution for your problem using jQuery:

Fiddle - http://jsfiddle.net/6QN77/2/

I didn't spend too much time cleaning up the JavaScript, but I'm leaving that to you now.

HTML

<ul id="searchselectors">
  <li class="group">Group name 1
    <ul>
      <li class="item selected">List item 1.1</li>
      <li class="item">List item 1.2</li>
      <li class="item">List item 1.3</li>
    </ul>
  </li>
  <li class="group">Group name 2
    <ul>
      <li class="item">List item 2.1</li>
      <li class="item">List item 2.2</li>
      <li class="item">List item 2.3</li>
    </ul>
  </li>
  <li class="group">Group name 3
    <ul>
      <li class="item">List item 3.1</li>
    </ul>
  </li>
</ul>

jQuery

$(function () {
    var $menu = $("#searchselectors"),
        $items = $menu.find(".item"),
        $selectedItem = $menu.find(".selected"),
        selectedIndex = $selectedItem.length - 1;

    $(document).on("keydown", function (e) {
        switch(e.keyCode) {
            case 40:  // down arrow
                $selectedItem.removeClass("selected");
                selectedIndex = (selectedIndex + 1) % $items.length;
                $selectedItem = $items.eq(selectedIndex).addClass("selected");
                break;
            case 38:  // up arrow
                $selectedItem.removeClass("selected");
                selectedIndex = (selectedIndex - 1) % $items.length;
                $selectedItem = $items.eq(selectedIndex).addClass("selected");
                break;
        }
    });
});

UPDATE : My solution revolves around getting a reference to a wrapper element ( #searchselectors ) and getting all the LI elements marked with the CSS class .item . Next I get a reference to the currently selected element and its index. Finally, the code listens to the down and up arrow keys being pressed ( keydown ), decrementing if going up and incrementing if going up. Cycling is achieved via the modulus operator. The selected item's CSS class is removed and put back. The selected item reference is used for performance reasons so I don't have to write $items.removeClass(".selected").eq(selectedIndex).addClass("selected");

In my quest to provide native JS answers to those looking for it, here is @Mario j Vargas' good answer adapted in native Javascript. It only takes 2 lines of extra code.

http://jsfiddle.net/kevinvanlierde/7tQSW/2/

Only putting the JS up here, HTML is the same.

(function () {
    var $menu = document.getElementById('searchselectors'),
        items = $menu.getElementsByClassName('item'),
        $selectedItem = $menu.getElementsByClassName('selected')[0],
        selectedIndex = Array.prototype.indexOf.call($selectedItem, items)+1;

    document.body.addEventListener('keydown', function (e) {
        switch(e.keyCode) {
            case 40:  // down arrow
                $selectedItem.className = $selectedItem.className.replace(' selected','');
                selectedIndex = selectedIndex < items.length - 1 ? selectedIndex + 1 : selectedIndex;
                $selectedItem = items[selectedIndex];
                $selectedItem.className += ' selected';
                break;
            case 38:  // up arrow
                $selectedItem.className = $selectedItem.className.replace(' selected','');
                selectedIndex = selectedIndex > 0 ? selectedIndex - 1 : selectedIndex;
                $selectedItem = items[selectedIndex];
                $selectedItem.className += ' selected';
                break;
        }
    }, false);
}());

Easiest way to get all the list items with class "item" is:

var items = $('.item'); 

 for (var i = 0; i < items.length; i++) {
      var item = items[i]; // iterate
 }

And then, you can select the next item from the list

OR

you can do this

 if (!$().next) {
    var nextUL= $().parent.find('ul')
    iterateThruList(nextUL);
 }

You could use something like

var UL = $(".searchselectors").children().length; //number of UL (group names)

to iterate through items.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM