Как реализовать функцию, которая скрывает множество элементов при клике вне их области?

Как реализовать функционал таким образом, чтобы, кликнув по одному из четырех идентичных по структуре блоков с различным содержимым, он открывался, а при клике вне этого блока, он закрывался? Чтобы при этом остальные блоки не открывались вместе с ним и работали независимо друг от друга. Вот мой текущий код:

```javascript
$(".filter-link").click(function() {
  $('.filter-block').toggle();
});

$(document).on('click', function(e) {
  if (!$(e.target).closest(".filter").length) {
    $('.filter-block').hide();
  }
  e.stopPropagation();
});

// Пример HTML-структуры одного из четырех блоков:
<form class="filter-form">
    <div class="filter">
        <a class="filter-link" href="#" onclick="$('.filter-block-cat').toggle();return false;">Категория</a>
        <ul class="filter-block filter-block-cat" aria-labelledby="filter-block" style="display:none;">
            // содержимое
        </ul>
    </div>
</form>
```

Сейчас, кликая по одному блоку, открываются сразу три других. Как модифицировать этот код, чтобы он соответствовал необходимому поведению?
  • 3 декабря 2023 г. 17:09
Ответы на вопрос 4
Чтобы реализовать описанное поведение, вам нужно уникализировать селекторы для каждого блока и работать с конкретным блоком, с которым взаимодействует пользователь. Кроме того, различные обработчики событий должны корректно определять, где был выполнен клик.

Вот пример того, как можно изменить ваш текущий код:

```javascript
// Для начала удалим обработчик onclick из HTML:
// onclick="$('.filter-block-cat').toggle();return false;" лучше не использовать инлайн JS

$(".filter-link").click(function(event) {
  // Запрещаем всплытие, чтобы document не сработал на этот клик
  event.preventDefault();
  event.stopPropagation();
  
  // Закрыть все filter-block, кроме текущего
  $('.filter-block').not($(this).next('.filter-block')).hide();
  
  // Переключаем видимость текущего filter-block
  $(this).next('.filter-block').toggle();
});

// Обработчик клика по всему документу
$(document).on('click', function(e) {
  // Если клик был не по блоку фильтра и не по ссылке, открывающей фильтр 
  if (!$(e.target).closest(".filter, .filter-link").length) {
    // то скрываем все блоки
    $('.filter-block').hide();
  }
});

// Пример HTML-структуры одного из четырех блоков оставляем без inline JS:
<form class="filter-form">
    <div class="filter">
        <a class="filter-link" href="#">Категория</a>
        <ul class="filter-block filter-block-cat" aria-labelledby="filter-block" style="display:none;">
            // содержимое
        </ul>
    </div>
</form>
```

Что изменено и почему:

1. Убран инлайновый JS `onclick` из HTML, потому что он не рекомендуется для управления событиями и затрудняет поддержку кода.
2. Один общий обработчик навешан на все ссылки с классом `.filter-link`. Он предотвращает выполнение стандартного действия ссылок и всплытие события.
3. Внутри обработчика происходит закрытие всех блоков `.filter-block`, кроме следующего за нажатой ссылкой (это и есть непосредственно связанный с ней блок с фильтрами).
4. Обработчик кликов по `document` скрывает все `.filter-block`, если клик был совершен вне блоков `.filter` и вне ссылок `.filter-link`.

После внесения этих изменений каждый блок с фильтрами будет открываться независимо друг от друга, и все они будут закрываться при клике вне их области.
Если вы хотите, чтобы блок с классом "filter1" скрывался при клике вне его, назначьте класс "external" внешнему блоку. Используйте этот код: 
 
```javascript
$(document).ready(function(){
    $(".external").click(function(){
        $(".filter1").hide();
    });
});
```
При клике на элемент с классом "external", блок "filter1" будет скрыт. Вы можете также управлять поведением нескольких блоков, если присвоите им одинаковые классы — они будут реагировать на события одновременно. Вместо класса или идентификатора можно использовать также тег, например "body" или "aside". Чтобы показать блок "filter1" по клику, замените метод "hide()" на "show()": 
```javascript
$(document).ready(function(){
    $(".external").click(function(){
        $(".filter1").show();
    });
});
```
Похожие вопросы