Javascript-форум (https://javascript.ru/forum/)
-   Events/DOM/Window (https://javascript.ru/forum/events/)
-   -   Активные ссылки с разными стилями. Чистый JS (https://javascript.ru/forum/events/85493-aktivnye-ssylki-s-raznymi-stilyami-chistyjj-js.html)

ixiz 19.09.2023 23:28

Активные ссылки с разными стилями. Чистый JS
 
Добрый день!

Есть список ссылок:

<ul class="nav-list">
     <li data-filter="red" class="nav-list__item" id="red">Красный</li>
     <li data-filter="green" class="nav-list__item" id="green">Зеленый</li>
     <li data-filter="blue" class="nav-list__item" id="blue">Синий</li>
     <li data-filter="gray" class="nav-list__item" id="gray">Сброс</li>
</ul>



Нужно, чтобы в активном (нажатом) состоянии к каждой ссылке применялся свой собственный стиль.

Проблема: если указать для активной ссылки класс 'active', то все активные ссылки будут иметь один стиль, а это меня не устраивает.

При клике на новую ссылку, класс 'active' удаляется у старой ссылки и добавляется к новой. Это меня устраивает.

navItems.forEach(item => {
	item.addEventListener('click', event => {
		const filterValue = event.target.dataset.filter;
		navItems.forEach(item => {
    	item.classList.remove('active');
		event.target.classList.add('active');
		});
		});
	});



Если вместо класса 'active' передавать значение dataset посредством переменной filterValue, к ссылкам применяются те классы, которые нужны. Это хорошо.

Но при этом класс у старой ссылки не удаляется, и когда происходит клик по новой ссылке, обе ссылки становятся активными. Это плохо.

navItems.forEach(item => {
item.addEventListener('click', event => {
const filterValue = event.target.dataset.filter;
item.classList.remove(filterValue);
event.target.classList.add(filterValue);
});
});


Подскажите, пожалуйста, как можно решить эту проблему.

Aetae 19.09.2023 23:41

<ul class="nav-list-1">
     <li data-filter="red" class="nav-list__item">Красный</li>
     <li data-filter="green" class="nav-list__item">Зеленый</li>
     <li data-filter="blue" class="nav-list__item">Синий</li>
     <li data-filter="gray" class="nav-list__item">Сброс</li>
</ul>
<style> 
  [data-filter="red"]:active {
    color: red
  }  
  [data-filter="green"]:active {
    color: green
  }  
  [data-filter="blue"]:active {
    color: blue
  }  
  [data-filter="gray"]:active {
    color: gray
  }  
</style>

<ul class="nav-list-2">
     <li style="--active-color: red" class="nav-list__item">Красный</li>
     <li style="--active-color: green" class="nav-list__item">Зеленый</li>
     <li style="--active-color: blue" class="nav-list__item">Синий</li>
     <li style="--active-color: gray" class="nav-list__item">Сброс</li>
</ul>
<style> 
  .nav-list-2 > li:active {
    color: var(--active-color);
  }  
</style>

ixiz 20.09.2023 00:41

Спасибо за оперативный ответ!

Наверно, я не совсем точно описал проблему. При ховере и клике (hover и active) у меня всё работает.

Мне надо, чтобы активная ссылка имела оформление не только в процессе клика, а на протяжении всего времени, пока юзер не кликнул на другую ссылку.

Собственно, проблема в том, что если в JS я пишу ‘active’, то КО ВСЕМ ссылкам применяется ОДИН CSS класс .active. А мне нужно, чтобы У КАЖДОЙ ссылки было свое оформление.

Если же в JS я меняю ‘active’ на переменную filterValue, я в принципе получаю желаемое: каждая ссылка имеет свое оформление: значение dataset совпадает с названием CSS класса. Но это оформление не отключается при клике на новую ссылку. Нажал на красную, красная ссылка стала красной, нажал на зеленую, зеленая стала зеленой. А мне надо, чтобы при клике на зеленую она стала зеленой, а красная перестала быть красной.

Как-то так.

рони 20.09.2023 01:42

ixiz,
<!DOCTYPE HTML>
<html>

<head>
    <title>Untitled</title>
    <meta charset="utf-8">
    <style type="text/css">
        .red {
            color: red;
        }

        .green {
            color: green;
        }

        .blue {
            color: blue;
        }

        .gray {
            color: gray;
        }
    </style>
    <script>
        document.addEventListener('DOMContentLoaded', () => {
            const nav = document.querySelector('.nav-list');
            let active, filterValue;
            nav.addEventListener('click', ({ target }) => {
                if (target = target.closest('[data-filter]')) {
                    if (active) {
                        active.classList.remove(filterValue)
                    }
                    active = target;
                    filterValue = target.dataset.filter;
                    active.classList.add(filterValue)
                }
            })
        })
    </script>
</head>

<body>
    <ul class="nav-list">
        <li data-filter="red" class="nav-list__item" id="red">Красный</li>
        <li data-filter="green" class="nav-list__item" id="green">Зеленый</li>
        <li data-filter="blue" class="nav-list__item" id="blue">Синий</li>
        <li data-filter="gray" class="nav-list__item" id="gray">Сброс</li>
    </ul>
</body>

</html>

рони 20.09.2023 01:47

Цитата:

Сообщение от ixiz
ОДИН CSS класс .active. А мне нужно, чтобы У КАЖДОЙ ссылки было свое оформление.

:-?
<!DOCTYPE HTML>
<html>

<head>
    <title>Untitled</title>
    <meta charset="utf-8">
    <style type="text/css">
        [data-filter="red"].active {
            color: red;
        }

         [data-filter="green"].active {
            color: green;
        }

         [data-filter="blue"].active {
            color: blue;
        }

         [data-filter="gray"].active {
            color: gray;
        }
    </style>
    <script>
        document.addEventListener('DOMContentLoaded', () => {
            const nav = document.querySelector('.nav-list');
            let active;
            nav.addEventListener('click', ({ target }) => {
                if (target = target.closest('[data-filter]')) {
                    if (active) {
                        active.classList.remove('active')
                    }
                    active = target;
                    active.classList.add('active')
                }
            })
        })
    </script>
</head>

<body>
    <ul class="nav-list">
        <li data-filter="red" class="nav-list__item" id="red">Красный</li>
        <li data-filter="green" class="nav-list__item" id="green">Зеленый</li>
        <li data-filter="blue" class="nav-list__item" id="blue">Синий</li>
        <li data-filter="gray" class="nav-list__item" id="gray">Сброс</li>
    </ul>
</body>

</html>

voraa 20.09.2023 08:08

Можно меньше CSS
<!DOCTYPE HTML>
<html>
 
<head>
    <title>Untitled</title>
    <meta charset="utf-8">
    <style type="text/css">
        [data-filter].active {
            color: var(--link-color);
        }
 
    </style>
    <script>
        document.addEventListener('DOMContentLoaded', () => {
            const nav = document.querySelector('.nav-list');
            let active;
            nav.addEventListener('click', ({ target }) => {
                if (target = target.closest('[data-filter]')) {
                    active?.classList.remove('active')
                    active = target;
                    active.style.setProperty('--link-color', active.dataset.filter);
                    active.classList.add('active')
                }
            })
        })
    </script>
</head>
 
<body>
    <ul class="nav-list">
        <li data-filter="red" class="nav-list__item" id="red">Красный</li>
        <li data-filter="green" class="nav-list__item" id="green">Зеленый</li>
        <li data-filter="blue" class="nav-list__item" id="blue">Синий</li>
        <li data-filter="gray" class="nav-list__item" id="gray">Сброс</li>
    </ul>
</body>
 
</html>

ixiz 20.09.2023 10:47

Спасибо большое за ответы!

Aetae 20.09.2023 13:45

ixiz, можно без js, но это уже на любителя:
<ul class="nav-list">
  <label>
    <input type="radio" name="color"/>
    <li style="--active-color: red" class="nav-list__item">
      Красный
    </li>
  </label>
  <label>
    <input type="radio" name="color"/>
    <li style="--active-color: green" class="nav-list__item">
      Зеленый
    </li>
  </label>
  <label>
    <input type="radio" name="color"/>
    <li style="--active-color: blue" class="nav-list__item">
      Синий
    </li>
  </label>
  <label>
    <input type="radio" name="color"/>
    <li style="--active-color: gray" class="nav-list__item">
      Сброс
    </li>
  </label>
</ul>

<style> 
  .nav-list input[type="radio"] {
    display: none;
  }
  .nav-list input[type="radio"]:checked + li {
    color: var(--active-color);
  }  
</style>



Кстати возможно тебе бы хватило :target если ссылки по хэшу.

voraa 20.09.2023 13:53

Aetae,
Оно конечно браузерами пропускается, но валидаторы вопят благим матом.
Дочерними элементами <ul> могут быть только <li>


Часовой пояс GMT +3, время: 09:52.