Я пытаюсь создать простое раскрывающееся меню из простого вложенного списка.

Я хочу сделать две вещи:

  • при нажатии на ссылку toggleClass для родительского элемента li с '.open'
  • удалить класс '.open' из всех li, когда пользователь щелкает в любом месте, кроме указанного выше

HTML должен выглядеть так:

<ul>
   <li class="parent-item">
      <a href="#">Link</a>
      <ul>
         <li><a href="#">Child</a></li>
         <li><a href="#">Child</a></li>
         <li><a href="#">Child</a></li>
      </ul>
   </li>
   <li><a href="#">Link</a></li>
   <li class="parent-item">
      <a href="#">Link</a>
      <ul>
         <li><a href="#">Child</a></li>
         <li><a href="#">Child</a></li>
         <li><a href="#">Child</a></li>
      </ul>
   </li>
</ul>

JQuery выглядит так:

$('html').click(function(e) {
      $('.parent-item').removeClass('open');    
      if($(e.target).parent().hasClass('parent-item')) {
         e.preventDefault();
         $(e.target).parent().toggleClass('open');
      }     
});

Строка removeClass мешает строке toggleClass, не позволяя toggleClass запускаться при втором щелчке.

Вот скрипка

Есть идеи, что я делаю неправильно?

1
user1444027 23 Дек 2015 в 15:28

2 ответа

Лучший ответ

Вы можете переместить класс удаления вниз и исключить текущий элемент

$('html').click(function(e) {
  var $curr;
  if ($(e.target).parent().hasClass('parent-item')) {
    e.preventDefault();
    $curr = $(e.target).parent().toggleClass('open');
  }
  $('.parent-item.open').not($curr).removeClass('open');
});
.parent-item > ul {
  display: none;
}
.parent-item.open > ul {
  display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
  <li class="parent-item">
    <a href="#">Link</a>
    <ul>
      <li><a href="#">Child</a>
      </li>
      <li><a href="#">Child</a>
      </li>
      <li><a href="#">Child</a>
      </li>
    </ul>
  </li>
  <li><a href="#">Link</a>
  </li>
  <li class="parent-item">
    <a href="#">Link</a>
    <ul>
      <li><a href="#">Child</a>
      </li>
      <li><a href="#">Child</a>
      </li>
      <li><a href="#">Child</a>
      </li>
    </ul>
  </li>
</ul>
1
Arun P Johny 23 Дек 2015 в 12:31

Я считаю, что это может быть немного проще, так как вы хотите сделать что-либо из этого, только если щелчок находится в пределах .parent-item:

// The second argument means we only get called if the click
// travels through a .parent-item en route to the HTML element
$('html').on("click", ".parent-item", function(e) {
  // Don't follow the link
  e.preventDefault();

  // Toggle 'open' on this .parent-item
  $(this).toggleClass('open');

  // Remove it from any *other* .parent-item that has it
  $('.parent-item.open').not(this).removeClass('open');
  // Ignores this one --^^^^^^^^^^
});

Живой пример:

// The second argument means we only get called if the click
// travels through a .parent-item en route to the HTML element
$('html').on("click", ".parent-item", function(e) {
  // Don't follow the link
  e.preventDefault();

  // Toggle 'open' on this .parent-item
  $(this).toggleClass('open');

  // Remove it from any *other* .parent-item that has it
  $('.parent-item.open').not(this).removeClass('open');
});
.open {
  background-color: yellow;
}
<ul>
   <li class="parent-item">
      <a href="#">Link</a>
      <ul>
         <li><a href="#">Child</a></li>
         <li><a href="#">Child</a></li>
         <li><a href="#">Child</a></li>
      </ul>
   </li>
   <li><a href="#">Link</a></li>
   <li class="parent-item">
      <a href="#">Link</a>
      <ul>
         <li><a href="#">Child</a></li>
         <li><a href="#">Child</a></li>
         <li><a href="#">Child</a></li>
      </ul>
   </li>
</ul>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

В комментариях вы сказали, что хотите, чтобы щелчок вне любого .parent-item также закрыл все открытые. Для этого мы немного подправим, вернувшись к вашему нефильтрованному обработчику кликов html:

// The second argument means we only get called if the click
// travels through a .parent-item en route to the HTML element
$('html').on("click", function(e) {
  // If this click came through a parent item, get it
  var parentItem = $(e.target).closest(".parent-item");

  // Remove 'open' from any *other* .parent-item that has it
  $('.parent-item.open').not(parentItem).removeClass('open');

  // Was this click on a .parent-item?
  if (parentItem.length) {
    // Don't follow the link
    e.preventDefault();

    // Toggle 'open' on this .parent-item
    parentItem.toggleClass('open');
  }
});

Живой пример:

// The second argument means we only get called if the click
// travels through a .parent-item en route to the HTML element
$('html').on("click", function(e) {
  // If this click came through a parent item, get it
  var parentItem = $(e.target).closest(".parent-item");
  
  // Remove 'open' from any *other* .parent-item that has it
  $('.parent-item.open').not(parentItem).removeClass('open');
  
  // Was this click on a .parent-item?
  if (parentItem.length) {
    // Don't follow the link
    e.preventDefault();

    // Toggle 'open' on this .parent-item
    parentItem.toggleClass('open');
  }
});
.open {
  background-color: yellow;
}
<ul>
   <li class="parent-item">
      <a href="#">Link</a>
      <ul>
         <li><a href="#">Child</a></li>
         <li><a href="#">Child</a></li>
         <li><a href="#">Child</a></li>
      </ul>
   </li>
   <li><a href="#">Link</a></li>
   <li class="parent-item">
      <a href="#">Link</a>
      <ul>
         <li><a href="#">Child</a></li>
         <li><a href="#">Child</a></li>
         <li><a href="#">Child</a></li>
      </ul>
   </li>
</ul>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
2
T.J. Crowder 23 Дек 2015 в 13:19